二叉排序树

二叉排序树

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;

2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

3)左、右子树也分别为二叉排序树;

 

       I.建树:

       初始时树为空。

对于第一个数,直接作为树的根结点。

       对于堆中的一个数,起始时设置与之比较的结点为树的根结点,该数与结点的值比较,若该数与结点的值相等,则无操作,结束;若该数比结点的值小,则结点变为结点的左子结点;若该数比结点的值大或等于(其它情况),则结点变为结点的右子结点。直到结点为空,则增加一个结点,为之前结点的左/右子结点,并写入数值。

       II.判断是否出现:

       对于一个需要判断的数,起始时设置与之比较的结点为树的根结点,该数与结点的值比较,若该数与结点的值相等,则该数在堆中出现,结束比较;若该数比结点的值小,则结点变为结点的左子结点;若该数比结点的值大,则结点变为结点的右子结点。直到结点为空,则该数在堆中没有出现,结束比较。

    III.输出:

任意一个结点,左子结点(如果有)的值小于等于该结点的值,右子结点(如果有)的值大于等于该结点的值。

    所以采用中序遍历(LDR),对于任意一个结点,输出的先后顺序(不一定相邻)为左子结点,根结点,右子结点。

 

建树保证满足二叉排序树 “对于树中的任意一个结点,若该结点有左子结点,则左子结点的值小于等于该结点的值,若该结点有右子结点,则右子结点的值大于等于该结点的值” 的性质:

新加入的数满足上述条件,而其它数没有变化,也满足上述条件。所以所有的点满足上述条件。

 

 

       建树和输出的时间复杂度都大约为树所有结点的高度之和。而当树满足线性结构时(内部结点的出度都为1),可用归纳假设证明树所有结点的高度之和最大。

1.结点为0的树满足当满足线性结构时,树所有结点的高度之和最大;

2.假设一棵结点数目为n的树,当满足线性结构时,树所有结点的高度之和最大。对于一棵结点数目为n的树增加一个结点,增加的结点高度最大为n,当树满足线性结构时成立。所以一棵结点数目为n+1的树,当满足线性结构时,树所有结点的高度之和最大。

所以得证。

 

 

建树+输出的最坏时间复杂度:

把数按照从小到大或从大到小的顺序加入树中,每次新的结点是上次结点的左/右子结点。树的深度为树所有结点的高度之和,大约为n*n/2,即建树和输出的时间复杂度都为O(n*n/2),总的时间复杂度为O(n*n)。

 

建树+输出的平均复杂度:O(nlogn)

 

判断是否出现平均时间复杂度:O(logn),最坏时间复杂度:O(n)。

 

 Code:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <malloc.h>
  4 
  5 //二叉排序树(判断一个数是否出现在一个序列中)
  6 //1.排序:相同的数要加进去
  7 //2.判断某些数是否在一个序列中
  8 //所以当序列加入二叉排序树中,相同的数不必加入
  9 //但是相同的数不必再加入:需要每次都判断两个数是否相同,时间消耗长,反不如让相同的数也加入树中(如果序列中的数基本不相同)
 10 
 11 struct node
 12 {
 13     long d;
 14     struct node *left;
 15     struct node *right;
 16 }*tree;
 17 
 18 void LDR(struct node *p)
 19 {
 20     if (p!=NULL)
 21     {
 22         LDR(p->left);
 23         printf("%ld ",p->d);
 24         LDR(p->right);
 25     }
 26 }
 27 
 28 int main()
 29 {
 30     struct node *p,*q;
 31     long n,m,s,i;
 32     scanf("%ld",&n);
 33     if (n>=1)
 34     {
 35         scanf("%ld",&s);
 36         tree=(struct node *) malloc (sizeof(struct node));
 37         tree->d=s;
 38         tree->left=NULL;
 39         tree->right=NULL;
 40     }
 41     for (i=2;i<=n;i++)
 42     {
 43         scanf("%ld",&s);
 44         p=(struct node *) malloc (sizeof(struct node));
 45         p=tree;
 46         while (p)
 47         {
 48             if (s<p->d)
 49             {
 50                 if (p->left!=NULL)
 51                     p=p->left;
 52                 else
 53                 {
 54                     q=(struct node *) malloc (sizeof(struct node));
 55                     q->d=s;
 56                     q->left=NULL;
 57                     q->right=NULL;
 58                     p->left=q;
 59                     break;
 60                 }
 61             }
 62             else
 63             {
 64                 if (p->right!=NULL)
 65                     p=p->right;
 66                 else
 67                 {
 68                     q=(struct node *) malloc (sizeof(struct node));
 69                     q->d=s;
 70                     q->left=NULL;
 71                     q->right=NULL;
 72                     p->right=q;
 73                     break;
 74                 }
 75             }
 76         }
 77     }
 78     scanf("%ld",&m);
 79     for (i=1;i<=m;i++)
 80     {
 81         scanf("%ld",&s);
 82         if (n==0)
 83         {
 84             printf("%ld do not exist\n",s);
 85             continue;
 86         }
 87         p=(struct node *) malloc (sizeof(struct node));
 88         p=tree;
 89         while (p)
 90         {
 91             if (p->d==s)
 92             {
 93                 printf("%ld exist\n",s);
 94                 break;
 95             }
 96             else if (s<p->d)
 97             {
 98                 if (p->left!=NULL)
 99                     p=p->left;
100                 else
101                 {
102                     printf("%ld do not exist\n",s);
103                     break;
104                 }
105             }
106             else
107             {
108                 if (p->right!=NULL)
109                     p=p->right;
110                 else
111                 {
112                     printf("%ld do not exist\n",s);
113                     break;
114                 }
115             }
116         }
117     }
118     //print tree
119     //任意一个结点,左子结点(如果有)的值小于该结点的值,右子结点(如果有)的值大于该结点的值
120     //所以采用中序遍历(LDR),对于任意一个结点,输出的先后顺序(不一定相邻)为左子结点,根结点,右子结点
121     printf("Ascending Order: ");
122     LDR(tree);
123     return 0;
124 }
125 /*
126 6
127 2 6 1 3 3 4
128 3
129 1 4 7
130 */

 

 

      

优化:

Size Balanced Tree(SBT)

AVL树

红黑树

Treap(Tree+Heap)

这些均可以使查找树的高度为O(log(n))。

 

 

 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

二叉排序树

——二叉排序树的值都不相同

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;

2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

3)左、右子树也分别为二叉排序树;

 

 

二叉排序树的修改版(这篇文章中简称为二叉排序树):

1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

3)左、右子树也分别为二叉排序树的修改版;

 

       I.建树:

       初始时树为空。

对于第一个数,直接作为树的根结点。

       对于堆中的一个数,起始时设置与之比较的结点为树的根结点,该数与结点的值比较,若该数与结点的值相等,则无操作,结束;若该数比结点的值小,则结点变为结点的左子结点;若该数比结点的值大,则结点变为结点的右子结点。直到结点为空,则增加一个结点,为之前结点的左/右子结点,并写入数值。

       II.判断是否出现:

       对于一个需要判断的数,起始时设置与之比较的结点为树的根结点,该数与结点的值比较,若该数与结点的值相等,则该数在堆中出现,结束比较;若该数比结点的值小,则结点变为结点的左子结点;若该数比结点的值大,则结点变为结点的右子结点。直到结点为空,则该数在堆中没有出现,结束比较。

 

 

       建树保证二叉排序树的值都不相同:

1.不加任何数时,二叉排序树的值都不相同。

2.假设某个数未加之前二叉排序树的值都不相同,加入数s后,

对于某个数s在建树中经过的所有结点,都有:

I.若从结点(值为t)到达结点的左子结点,则s<t<该结点的右子树的所有结点的数值,即与该结点的右子树的所有结点的数值都不相同。

II.若从结点(值为t)到达结点的右子结点,则s>t>该结点的左子树的所有结点的数值,即与该结点的左子树的所有结点的数值都不相同。

III.若该结点的数值(值为t)等于数s,则s=t>该结点的左子树的所有结点的数值,s=t<该结点的右子树的所有结点的数值。

所以加入该数后,二叉排序树的值仍然都不相同。

所以建树保证二叉排序树的值都不相同。

 

例子:

 

建树保证满足二叉排序树 “对于树中的任意一个结点,若该结点有左子结点,则左子结点的值小于等于该结点的值,若该结点有右子结点,则右子结点的值大于等于该结点的值” 的性质:

新加入的数满足上述条件,而其它数没有变化,也满足上述条件。所以所有的点满足上述条件。

 

 

       建树和输出的时间复杂度都大约为树所有结点的高度之和。而当树满足线性结构时(内部结点的出度都为1),可用归纳假设证明树所有结点的高度之和最大。

1.结点为0的树满足当满足线性结构时,树所有结点的高度之和最大;

2.假设一棵结点数目为n的树,当满足线性结构时,树所有结点的高度之和最大。对于一棵结点数目为n的树增加一个结点,增加的结点高度最大为n,当树满足线性结构时成立。所以一棵结点数目为n+1的树,当满足线性结构时,树所有结点的高度之和最大。

所以得证。

 

 

建树+输出的最坏时间复杂度:

把数按照从小到大或从大到小的顺序加入树中,每次新的结点是上次结点的左/右子结点。树的深度为树所有结点的高度之和,大约为n*n/2,即建树和输出的时间复杂度都为O(n*n/2),总的时间复杂度为O(n*n)。

 

建树+输出的平均复杂度:O(nlogn)

 

判断是否出现平均时间复杂度:O(logn),最坏时间复杂度:O(n)。

 

 Code:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <malloc.h>
  4 
  5 //二叉排序树(判断一个数是否出现在一个序列中)
  6 //1.排序:相同的数要加进去
  7 //2.判断某些数是否在一个序列中
  8 //所以当序列加入二叉排序树中,相同的数不必加入
  9 //但是相同的数不必再加入:需要每次都判断两个数是否相同,时间消耗长,反不如让相同的数也加入树中(如果序列中的数基本不相同)
 10 
 11 struct node
 12 {
 13     long d;
 14     struct node *left;
 15     struct node *right;
 16 }*tree;
 17 
 18 void LDR(struct node *p)
 19 {
 20     if (p!=NULL)
 21     {
 22         LDR(p->left);
 23         printf("%ld ",p->d);
 24         LDR(p->right);
 25     }
 26 }
 27 
 28 int main()
 29 {
 30     struct node *p,*q;
 31     long n,m,s,i;
 32     scanf("%ld",&n);
 33     if (n>=1)
 34     {
 35         scanf("%ld",&s);
 36         tree=(struct node *) malloc (sizeof(struct node));
 37         tree->d=s;
 38         tree->left=NULL;
 39         tree->right=NULL;
 40     }
 41     for (i=2;i<=n;i++)
 42     {
 43         scanf("%ld",&s);
 44         p=(struct node *) malloc (sizeof(struct node));
 45         p=tree;
 46         while (p)
 47         {
 48             if (s<p->d)
 49             {
 50                 if (p->left!=NULL)
 51                     p=p->left;
 52                 else
 53                 {
 54                     q=(struct node *) malloc (sizeof(struct node));
 55                     q->d=s;
 56                     q->left=NULL;
 57                     q->right=NULL;
 58                     p->left=q;
 59                     break;
 60                 }
 61             }
 62             else
 63             {
 64                 if (p->right!=NULL)
 65                     p=p->right;
 66                 else
 67                 {
 68                     q=(struct node *) malloc (sizeof(struct node));
 69                     q->d=s;
 70                     q->left=NULL;
 71                     q->right=NULL;
 72                     p->right=q;
 73                     break;
 74                 }
 75             }
 76         }
 77     }
 78     scanf("%ld",&m);
 79     for (i=1;i<=m;i++)
 80     {
 81         scanf("%ld",&s);
 82         if (n==0)
 83         {
 84             printf("%ld do not exist\n",s);
 85             continue;
 86         }
 87         p=(struct node *) malloc (sizeof(struct node));
 88         p=tree;
 89         while (p)
 90         {
 91             if (p->d==s)
 92             {
 93                 printf("%ld exist\n",s);
 94                 break;
 95             }
 96             else if (s<p->d)
 97             {
 98                 if (p->left!=NULL)
 99                     p=p->left;
100                 else
101                 {
102                     printf("%ld do not exist\n",s);
103                     break;
104                 }
105             }
106             else
107             {
108                 if (p->right!=NULL)
109                     p=p->right;
110                 else
111                 {
112                     printf("%ld do not exist\n",s);
113                     break;
114                 }
115             }
116         }
117     }
118     //print tree
119     //任意一个结点,左子结点(如果有)的值小于该结点的值,右子结点(如果有)的值大于该结点的值
120     //所以采用中序遍历(LDR),对于任意一个结点,输出的先后顺序(不一定相邻)为左子结点,根结点,右子结点
121     printf("Ascending Order: ");
122     LDR(tree);
123     return 0;
124 }
125 /*
126 6
127 2 6 1 3 3 4
128 3
129 1 4 7
130 */

 

 

 

      

优化:

Size Balanced Tree(SBT)

AVL树

红黑树

Treap(Tree+Heap)

这些均可以使查找树的高度为O(log(n))。

 

 

/////////////////////////////////////////////////////////////////////////////////

某种求法的错误性:

 

 

 

当t->lson/rson为空时,call InsertNode()。然后t=nil,对t赋值为s,但之前的t->lson/rson仍为空。所以不能这样做,必须在t->lson/rson为空时,修改t->lson/rson的值。

posted @ 2017-05-27 00:09  congmingyige  阅读(318)  评论(0编辑  收藏  举报