在c中验证BST的最佳方法

时间:2017-07-27 02:22:45

标签: c binary-search-tree

我刚刚开始学习树木,我编写了代码来验证树木是否是BST天气,我想知道是否有更好的方法来实现它,而不是我现在正在做的事情。我现在正在做的就是我将每个节点中的所有值都推送到堆栈中,而不是通过该堆栈来检查每个值是否小于先前的值。我觉得现在代码的运行时间太高以及时间复杂度。

    // this code is to check if a binary tree is a BST

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 256

int A[MAX_SIZE];
int top;

typedef struct node{
    int data;
    struct node* right;
    struct node* left;
}node;

node* Insert(node* root, int data);
void Inorder(node* root);
node* GetNewNode(int data);

void Push(int x){
    A[++top] = x;
}

void Pop(){
    top--;
}

int Top(){
    return A[top];
}

int main(void){
    int data, x, lastValue;
    int BST;
    node* root = NULL;
    printf("how many elements would you like to be in the tree\n");
    scanf("%i", &x);
    for(int i = 0; i < x; i++){
        scanf("%i", &data);
        root = Insert(root, data);
    }
    Inorder(root);
    for(int i = 0; i < MAX_SIZE; i++){
        x = Top();
        if(i >= 1){
            if(top < 0){
                break;
            }
            if(lastValue > x){
                BST = 1;
            }
            else{
                BST = 0;
                break;
            }
        }

        lastValue = x;

        Pop();
    }
    if(!BST){
        printf("not a BST\n");
    }
    else{
        printf("BST\n");
    }
}

node* Insert(node* root, int data){
    if(root == NULL){
        root = GetNewNode(data);
    }
    else if(data <= root->data){
        root->left = Insert(root->left, data);
    }
    else{
        root->right= Insert(root->right, data);
    }
    return root;
}

node* GetNewNode(int data){
    node* newNode = (node*)malloc(sizeof(node));
    newNode->data = data;
    newNode->left = newNode->right = NULL;
    return newNode;
}

void Inorder(node* root){
    if(root == NULL){
        return;
    }
    Inorder(root->left);
    Push(root->data);
    Inorder( root->right);
}

4 个答案:

答案 0 :(得分:1)

无需使用额外的数据结构来验证某些内容是否为二叉搜索树。 @Jonathan Leffer在评论中建议的几乎是正确的(它错过了一个非常重要的边缘情况),并且它没有完全检查你的二叉搜索树以获得最佳结构。

二进制搜索树,顾名思义,是一种基本上用其结构实现二进制搜索的树。这意味着当你遍历树时,你想确保它被“排序”(我稍后会定义),并确保它是平衡的。这将确保您的二叉搜索树实际上在O(log n)时间内运行搜索。

首先,您需要检查排序。这是最容易做到的,不允许重复:在这种情况下,你需要做的大部分是遍历树,检查每个节点左右儿童是否小于和大于(分别,如果它们存在),当前节点。这大多是正确的,如果插入和新方法正常运行,则永远不会导致逻辑错误。但如果他们不这样做,你可以得到这样的案例:

        12
       /  \
      8    95 
     / \
    7   13

你会注意到这个“二叉搜索树”到目前为止满足了我们的所有要求,但实际上并不是bst。搜索13时,它不会返回正确的值(它会说13不在树中)。要纠正这个问题,您需要跟踪限制值(在这种情况下为12),并将其与应该小于它的所有值进行比较,但可能不在实践中。

然后,我们需要处理平衡问题。在这一点上,我们确保任何bst都是正确的,如果这对你来说足够了,那么随意停止阅读。但是,避免这种情况可能会对运行时产生很大的问题,如果你想要一个真正的 bst,你可能想要继续阅读。

平衡是二元搜索树的一个大问题。考虑这棵树:

  12
    \
     13
       \
        14
          \ 
           15
             \
              16

根据我们的规则,这是一个有效的树,但它相当于一个链表,这意味着插入将在O(n)时间运行,正是bst应该避免的!

这可以通过另一个简单的规则来避免:bst节点的“side”没有“高度”大于另一边的一个。

要理解这条规则,我们需要了解侧面和高度。 Side指的是给定节点的右子节点及其子节点。高度是子节点的层数,递归地定义为每个节点的子节点的高度的最大值加1,其中基本情况是空节点,其高度为0。

此时,您对平衡有一个连贯的定义,但是在插入内容时如何保留它。对于任何给定的插入,您可能会使树失去平衡!

因为这个帖子是漫无目的的,所以我只会溢出豆子:假设在插入之前树是平衡的,那么在与不平衡相反的方向上旋转最低的不平衡节点。如果仍然产生不平衡树(因为这是一种情况),请在与尝试旋转相反的方向上旋转不平衡侧一次。实际编程时需要4个案例。

我知道这是一个信息转储,但没有正确使用bst可能会导致各种麻烦。我希望这有帮助!

答案 1 :(得分:0)

BST遵循的一个简单条件是 - 在inorder遍历中,元素将按升序排列。

此后的任何树都是BST。 (也许是平衡与否,但我认为这不是你所需要的。)

这是检查inorder遍历的简单代码

(假设树只包含正元素,但可以轻松删除该限制)

int check(Node *node, int last) {
    if (node == NULL)
        return last;
    int left = check(node->left, last);
    if (left == -1)
        return -1;
    if (left > node->val)
        return -1;
    return check(node->right, node->val);
}

然后你调用check(root,0)。如果它不是BST,它将返回-1。否则它将返回树中最大的数字。

答案 2 :(得分:0)

顺序遍历可以通过更改树中的链接来迭代完成(两次,一次设置叶节点右链接到后继节点,再次将其恢复为null)。该算法称为Morris遍历。 Morris遍历函数的大多数实现都扫描整个树,而不是按顺序返回到节点的链接。下面的示例代码使用指向根节点的指针调用,并且每个调用以遍历顺序返回指向节点的指针。在此示例中,逻辑的一部分位于main()中,其中对遍历函数的后续调用使用最后返回的节点的右指针作为参数。这可以在跟随右指针的第二个函数中实现,然后调用主遍历函数。

/* mrstrv2.c - morris traversal of binary tree */
/* MorrisTraversal returns a set of pointers to nodes */

#include<stdio.h>
#include<stdlib.h>

/* binary tree node */
typedef struct BTNODE_
{
    struct BTNODE_* left;
    struct BTNODE_* right;
    int data;
}BTNODE;

/* traverse binary tree without stack */
/* initial input parameter is pointer to root */
/* predecessor of cur is largest value < cur */
/* predecessor of cur = cur->left->right->right->right ... */
BTNODE * MorrisTraversal(BTNODE *cur)
{
BTNODE *pre;
    if(cur == NULL)
        return(NULL);
    while(cur != NULL){
        /* if left end of branch, return */
        if(cur->left == NULL)
            return(cur);
        /* advance pre to predecessor of cur */
        pre = cur->left;
        while(pre->right != NULL && pre->right != cur)
            pre = pre->right;
        /* if right end of branch, change pre->right = cur */
        /*  and advance cur left */
        if(pre->right == NULL){
            pre->right = cur;
            cur = cur->left;
        /* else back at cur, so restore pre->right = NULL */
        /*  and return */
        } else {
            pre->right = NULL;
            return(cur);
        }
    }
    return(NULL);
}

BTNODE* newbtNode(int data)
{
BTNODE* btNode = (BTNODE*) malloc(sizeof(BTNODE));
    btNode->left = NULL;
    btNode->right = NULL;
    btNode->data = data;
    return(btNode);
}

int main()
{
/* create a binary search tree */
BTNODE *root = newbtNode(8);
BTNODE *cur;
    root->left                = newbtNode( 4);
    root->left->left          = newbtNode( 2);
    root->left->left->left    = newbtNode( 1);
    root->left->left->right   = newbtNode( 3);
    root->left->right         = newbtNode( 6);
    root->left->right->left   = newbtNode( 5);
    root->left->right->right  = newbtNode( 7);
    root->right               = newbtNode(12);
    root->right->left         = newbtNode(10);
    root->right->left->left   = newbtNode( 9);
    root->right->left->right  = newbtNode(11);
    root->right->right        = newbtNode(14);
    root->right->right->left  = newbtNode(13);
    root->right->right->right = newbtNode(15);
    /* traverse the tree in order, one node at a time */
    /* note cur is advanced to cur->right with each iteration */
    for(cur = root; cur; cur = cur->right){
        cur = MorrisTraversal(cur);
        printf("%2d ", cur->data);
    }
    return 0;
}

答案 3 :(得分:0)

这是我的表现:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct node
{
    int data;
    struct node* left;
    struct node* right;
};

int isBSTUtil(struct node* node, int min, int max);

/* Returns true if the given tree is a binary search tree 
 (efficient version). */
int isBST(struct node* node) 
{ 
  return(isBSTUtil(node, INT_MIN, INT_MAX)); 
} 

/* Returns true if the given tree is a BST and its 
   values are >= min and <= max. */
int isBSTUtil(struct node* node, int min, int max) 
{ 
  /* an empty tree is BST */
  if (node==NULL) 
     return 1;

  /* false if this node violates the min/max constraint */ 
  if (node->data < min || node->data > max) 
     return 0; 

  /* otherwise check the subtrees recursively, 
   tightening the min or max constraint */
  return
    isBSTUtil(node->left, min, node->data-1) &&  // Allow only distinct values
    isBSTUtil(node->right, node->data+1, max);  // Allow only distinct values
} 

/* Helper function that allocates a new node with the
   given data and NULL left and right pointers. */
struct node* newNode(int data)
{
  struct node* node = (struct node*)
                       malloc(sizeof(struct node));
  node->data = data;
  node->left = NULL;
  node->right = NULL;

  return(node);
}

/* Driver program to test above functions*/
int main()
{
  struct node *root = newNode(4);
  root->left        = newNode(2);
  root->right       = newNode(5);
  root->left->left  = newNode(1);
  root->left->right = newNode(3); 

  if(isBST(root))
    printf("Is BST");
  else
    printf("Not a BST");

  getchar();
  return 0;
}