我刚刚开始学习树木,我编写了代码来验证树木是否是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);
}
答案 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;
}