C++ 在BST中查找交换的节点

C++ 在BST中查找交换的节点,c++,algorithm,data-structures,tree,binary-search-tree,C++,Algorithm,Data Structures,Tree,Binary Search Tree,我正在尝试编写一个程序,可以检测和打印BST中已交换的两个节点 在一个三层树中,我使用这种方法接近解决方案 If (!AllSubTreeAreValid()) { //Nodes swapped on same side of main root node } else { int max = getMax(root->left); int min = getMin(root->right); if(max > root->data || min <

我正在尝试编写一个程序,可以检测和打印BST中已交换的两个节点

在一个三层树中,我使用这种方法接近解决方案

If (!AllSubTreeAreValid())
{
//Nodes swapped on same side of main root node
}
else
{
  int max = getMax(root->left);
  int min = getMin(root->right);
  if(max > root->data || min < root->data )
  {
     //Nodes swapped on different sides of main root node
     //Print max and min values

  }
else 
{
 //No node swappped
}
}

//Helper functions
int GetMaxEle(TreeNode* tree)
{
    while(tree->right!=NULL)
    {
        tree=tree->right;
    }
    return tree->info;
}

int GetMinEle(TreeNode* tree)
{
    while(tree->left!=NULL)
    {
        tree=tree->left;
    }
    return tree->info;
}
在根节点15的右子树中,12更大(违例)

在根节点15的左子树中,16更大(违例)


那么,16、12是上述BST中交换的元素。我如何通过程序找到它们

我猜你的getMin et getMax与树是BST的假设是一致的,所以

T getMax(tree) {
  return tree -> right == null 
    ? tree -> value 
    : getMax(tree -> right);
}
(或具有循环的等效代码)。 如果是这样,代码最多检查树中的三个值。即使getMax和getMin遍历整个树以获得实际的max/min,您的测试仍然只基于两个比较。如果您想检查您的树是否满足BST属性,很明显,您必须检查所有的值。它足以将每个节点与其父节点进行比较

void CheckIsBst(Tree *tree) {
  if (tree -> left != null) {
    if (tree -> left -> value > tree -> value) {
      // print violation
    }
    CheckIsBst(tree -> left);   
  }
  // same with -> right, reversing < to > in the test
}
void CheckIsBst(树*Tree){
如果(树->左!=空){
如果(树->左->值->树->值){
//打印冲突
}
选中ISBST(树->左);
}
//与->右侧相同,在测试中反转
}
编辑:这是错误的,请参阅评论。我相信这个没问题

void checkIsBst(Tree *Tree, Tree *lowerBound, Tree *upperBound) {
  if(lowerBound!= null && lowerBound -> value > tree -> Value) {
    //violation
  }
  // same for upper bound, check with <
  if (tree -> left != null) {
    if (tree -> left -> value > tree -> value) {
      // print violation
     }
     CheckIsBst(tree -> left, lowerBound, tree);   
  }
  // same for right, reversing comparison 
  // setting lowerBound to tree instead of upperBound
}
void checkIsBst(树*Tree,树*lowerBound,树*upperBound){
if(lowerBound!=null&&lowerBound->value>tree->value){
//违反
}
//上限相同,请与检查<
如果(树->左!=空){
如果(树->左->值->树->值){
//打印冲突
}
选中ISBST(树->左,下边框,树);
}
//右侧相同,反向比较
//将lowerBound设置为tree而不是Upper Bound
}

使用空边界从根调用

考虑此问题的一种方法是使用这样一个事实,即树的无序遍历将按排序顺序生成所有元素。如果您可以在此漫游过程中检测到与排序顺序的偏差,则可以尝试定位位于错误位置的两个元素

让我们先看看如何对一个简单的排序数组执行此操作,然后将使用我们的算法构建在树上工作的东西。直观地说,如果我们从一个排序的数组开始,然后交换两个(不相等的!)元素,我们最终会发现数组中的一些元素不合适。例如,给定数组

1 2 3 4 5
如果我们交换2和4,我们将得到以下数组:

1 4 3 2 5
我们如何检测到2和4在这里交换?因为4是两个元素中较大的一个,并且向下交换,所以它应该大于它周围的两个元素。类似地,因为2被交换了,所以它应该比它周围的两个元素都小。由此,我们可以得出结论,2和4被交换了

但是,这并不总是正确的。例如,假设我们交换1和4:

4 2 3 1 5
这里,2和1都比它们的相邻元素小,4和3都比它们的相邻元素大。从这一点我们可以看出,这四个中有两个不知怎么被交换了,但我们不清楚应该交换哪一个。然而,如果我们取这些值中的最大值和最小值(分别为1和4),我们最终会得到交换的一对

更一般地说,要查找在序列中交换的元素,您需要查找

  • 阵列中最大的局部最大值
  • 数组中最小的局部最小值
这两个元素不合适,应该交换

现在,让我们考虑如何将其应用于树。由于树的按序遍历将产生两个元素无序的排序序列,因此一个选项是遍历树,记录我们找到的元素的按序序列,然后使用上述算法。例如,考虑你最初的BST:

              20
         /         \
      15             30
     /   \         /   \ 
   10    17      25     33
  / |   /  \    /  \    |  \
9  16  12  18  22  26  31  34
如果我们把它线性化成一个数组,我们得到

9 10 16 15 12 17 18 20 22 25 26 30 31 33 34
请注意,16大于其周围元素,12小于其周围元素。这立即告诉我们12和16被交换了

因此,解决这个问题的一个简单算法是对树进行有序遍历,将其线性化为一个序列,如
向量
deque
,然后扫描该序列以找到最大的局部最大值和最小的局部最小值。这将在O(n)时间内运行,使用O(n)空间。一个更复杂但更节省空间的算法是一次只跟踪三个节点——当前节点、其前一个节点和后一个节点——这将内存使用率降低到O(1)


希望这有帮助

如果您确定只有一个交换,则templatetypedef完成的树遍历将起作用。否则,我建议基于初始代码的解决方案:

int GetMax(TreeNode* tree) {
    int max_right, max_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        max_left = GetMax(tree->left);
        if (max_left > ret)
            ret = max_left;
    }
    if (tree->right != NULL) {
        max_right = GetMax(tree->right);
        if (max_right > ret)
            ret = max_right;
    }

    return ret;
}

int GetMin(TreeNode* tree) {
    int min_right, min_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        min_left = GetMin(tree->left);
        if (min_left < ret)
            ret = min_left;
    }
    if (tree->right != NULL) {
        min_right = GetMin(tree->right);
        if (min_right < ret)
            ret = min_right;
    }

    return ret;
}

void print_violations(TreeNode* tree) {
    if ((tree->left != NULL) && (tree->right != NULL)) {
        int max_left = GetMax(tree->left);
        int min_right = GetMin(tree->right);
        if (max_left > tree->data && min_right < tree->data) {
            printf("Need to swap %d with %d\n", max_left, min_right);
        }
    }
    if (tree->left != NULL)
        print_violations(tree->left);
    if (tree->right != NULL)
        print_violations(tree->right);
}
intgetmax(树节点*tree){
int max_right,max_left,ret;
ret=树->数据;
如果(树->左!=空){
max_left=GetMax(树->左);
如果(最大左>后)
ret=左最大值;
}
如果(树->右!=空){
max\u right=GetMax(树->右);
如果(最大右>返回)
ret=最大向右;
}
返回ret;
}
int GetMin(树节点*tree){
int minu_right,minu left,ret;
ret=树->数据;
如果(树->左!=空){
min_left=GetMin(树->左);
如果(最小左右!=空){
min_right=GetMin(树->右);
如果(最小右左!=NULL)&&(树->右!=NULL)){
int max_left=GetMax(树->左);
int min_right=GetMin(树->右);
如果(最大左>树->数据和最小右<树->数据){
printf(“需要将%d与%d交换\n”,左最大,右最小);
}
}
如果(树->左!=空)
打印违规(树->左);
如果(树->右!=空)
打印冲突
int GetMax(TreeNode* tree) {
    int max_right, max_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        max_left = GetMax(tree->left);
        if (max_left > ret)
            ret = max_left;
    }
    if (tree->right != NULL) {
        max_right = GetMax(tree->right);
        if (max_right > ret)
            ret = max_right;
    }

    return ret;
}

int GetMin(TreeNode* tree) {
    int min_right, min_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        min_left = GetMin(tree->left);
        if (min_left < ret)
            ret = min_left;
    }
    if (tree->right != NULL) {
        min_right = GetMin(tree->right);
        if (min_right < ret)
            ret = min_right;
    }

    return ret;
}

void print_violations(TreeNode* tree) {
    if ((tree->left != NULL) && (tree->right != NULL)) {
        int max_left = GetMax(tree->left);
        int min_right = GetMin(tree->right);
        if (max_left > tree->data && min_right < tree->data) {
            printf("Need to swap %d with %d\n", max_left, min_right);
        }
    }
    if (tree->left != NULL)
        print_violations(tree->left);
    if (tree->right != NULL)
        print_violations(tree->right);
}