C语言实现二叉查找树
来源:互联网 发布:乌云漏洞数据库 编辑:程序博客网 时间:2024/05/17 06:42
基本概念
首先二叉查找树是二叉树,回顾一下二叉树的概念,二叉树的每个节点都不能有多于两个的儿子,一般二叉树如下
二叉树的性质
二叉树有以下几个性质:TODO(上标和下标)
性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)。
性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。
性质3:包含n个结点的二叉树的高度至少为log2 (n+1)。
性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。
性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)
证明:下面用”数学归纳法”进行证明。
(01) 当i=1时,第i层的节点数目为2{i-1}=2{0}=1。因为第1层上只有一个根结点,所以命题成立。
(02) 假设当i>1,第i层的节点数目为2{i-1}。这个是根据(01)推断出来的!
下面根据这个假设,推断出”第(i+1)层的节点数目为2{i}”即可。
由于二叉树的每个结点至多有两个孩子,故”第(i+1)层上的结点数目” 最多是 “第i层的结点数目的2倍”。即,第(i+1)层上的结点数目最大值=2×2{i-1}=2{i}。
故假设成立,原命题得证!
性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)
证明:在具有相同深度的二叉树中,当每一层都含有最大结点数时,其树中结点数最多。利用”性质1”可知,深度为k的二叉树的结点数至多为:
20+21+…+2k-1=2k-1
故原命题得证!
性质3:包含n个结点的二叉树的高度至少为log2 (n+1)
证明:根据”性质2”可知,高度为h的二叉树最多有2{h}–1个结点。反之,对于包含n个节点的二叉树的高度至少为log2(n+1)。
性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1
证明:因为二叉树中所有结点的度数均不大于2,所以结点总数(记为n)=”0度结点数(n0)” + “1度结点数(n1)” + “2度结点数(n2)”。由此,得到等式一。
(等式一) n=n0+n1+n2
另一方面,0度结点没有孩子,1度结点有一个孩子,2度结点有两个孩子,故二叉树中孩子结点总数是:n1+2n2。此外,只有根不是任何结点的孩子。故二叉树中的结点总数又可表示为等式二。
(等式二) n=n1+2n2+1
由(等式一)和(等式二)计算得到:n0=n2+1。原命题得证!
满二叉树,完全二叉树和二叉查找树
满二叉树
定义:高度为h,并且由2{h} –1个结点的二叉树,被称为满二叉树。
完全二叉树
定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下一层的叶结点集中在靠左的若干位置上。这样的二叉树称为完全二叉树。
特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。
二叉查找树
定义:二叉查找树(Binary Search Tree),又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。
在二叉查找树中:
(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树。
(04) 没有键值相等的节点(no duplicate nodes)。
在实际应用中,二叉查找树的使用比较多。下面,用C语言实现二叉查找树。
首先定义头文件
#ifndef BSTREE_H_INCLUDED#define BSTREE_H_INCLUDEDtypedef int elementType;//定义结点值类型//定义结点typedef struct node{ elementType key; int height;//当前结点高度 struct node *left; struct node *right; struct node *parent;} bsNode, *bsTree;bsNode* create_node(elementType key,bsNode *left,bsNode *right,bsNode *parent);//创建结点bsTree bstree_insert(bsTree tree,elementType key);bsNode* insert_node(bsTree tree ,bsNode *node);//向树中插入结点bsNode* dele_node(bsTree tree ,bsNode *node);//删除结点void pre_order_tree(bsTree tree);void in_order_tree(bsTree tree);void post_order_tree(bsTree tree);bsNode *maximum_node(bsTree tree);//寻找树中最大结点bsNode *minimun_node(bsTree tree);//寻找树中最小结点int get_tree_height(bsTree tree);#endif // BSTREE_H_INCLUDED
在bstree.c中定义头文件中申明的函数
一棵二叉树是有由一个个结点组成的,我们先定义一个创建结点的函数
bsNode* create_node(elementType key,bsNode *left,bsNode *right,bsNode *parent){ bsNode *node; node=(bsNode *)malloc(sizeof(bsNode)); if(node==NULL) { printf("结点创建失败"); } node->key=key; node->left=left; node->right=right; node->parent=parent; return node;}
插入操作
有了结点后我们需要将一个个结点插入二叉树才行吧,其中插入操作用temp指针指向当前结点位置,因为二叉查找树是有序树,所以我们要先找到要插入结点该插入的位置,当temp从while中跳出来时候,说明已经找到要插入的位置了,pre指针指向temp前一个位置,也就是说while结束时pre是要插入结点node的父节点
bsNode* insert_node(bsTree tree ,bsNode *node){ if(node==NULL) { return NULL; } bsNode *temp,*pre; pre=NULL; temp=tree; while(temp) { pre=temp; if(temp->key<node->key) { temp=temp->right; } else { temp=temp->left; } } //while结束循环时pre指向node的父节点 if(tree==NULL) { tree=node; } else { node->parent=pre; if(pre->key<node->key) { pre->right=node; } else { pre->left=node; } } return tree;}bsTree bstree_insert(bsTree tree,elementType key){ bsNode *node=create_node(key,NULL,NULL,NULL); return insert_node(tree,node);}
删除操作
删除操作需要根据要删除结点node的位置分情况讨论
A.node没有同时有左右孩子结点,也就是说node是叶子或者node有独子,那么可以通过将node的父结点指向node的孩子就行(没有孩子就指向kong)B.node有左右孩子,那么一般的策略是将node右子树中最小结点的值赋值给node,这样就保证了二叉树的有序性,同时将右子树中最小结点删除。
/* 删除操作需要讨论要删除结点node的孩子情况 1.node没有两个孩子,也就是node有独子或者无子,那么直接将node父节点指向node的孩子(node无子也就指向null),然后free(node) 2.node有两个孩子,一般策略是将node右孩子子树中最小的结点赋值给node,然后删除最小孩子结点。(这么做会导致二叉树越来越失衡,后面AVL会讲到可以先比较node左右孩子结点的深度, 取深度大的一边赋值给node,然后删除相应的结点,其中node左子树那么就取最大的结点,右子树就取最小的)*/bsNode* dele_node(bsTree tree ,bsNode *node){ if(node==NULL||tree==NULL) return tree; if(tree->key>node->key)//要删除的结点在tree的左子树 { tree->left= dele_node(tree->left,node); } else if(tree->key<node->key)//要删除的结点在右子树 { tree->right= dele_node(tree->right,node); } else//找到要删除的结点了 { //node结点有左右孩子 if(tree->left&&tree->right) { bsNode *min=minimun_node(tree->right); tree->key=min->key; tree->right=dele_node(tree->right,min); } else { /* if(tree->left==NULL) { return tree->right;//右孩子是不是NULL无所谓 } else { return tree->left; } */ return tree=tree->left?tree->left:tree->right;//node左子树不为空就返回,为空就返回右子树(不管右子树是不是null) } }}
删除操作中涉及一个求最小结点的函数
bsNode *minimun_node(bsTree tree){ if(tree->left) { tree=tree->left; } return tree;}
最后就是遍历二叉树
//前序遍历二叉树void pre_order_tree(bsTree tree){ if(tree) { printf("%d ",tree->key); pre_order_tree(tree->left); pre_order_tree(tree->right); }}void in_order_tree(bsTree tree){ if(tree) { in_order_tree(tree->left); printf("%d ",tree->key); in_order_tree(tree->right); }}void post_order_tree(bsTree tree){ if(tree) { post_order_tree(tree->left); post_order_tree(tree->right); printf("%d ",tree->key); }}
测试代码
我们插入值为1,5,4,3,2,10,6,11,12的结点
bsTree tree=NULL; int a[]= {1,5,4,3,2,10,6,11,12}; int size=LENGTH(a); for(int i=0; i<size; i++) { tree=bstree_insert(tree,a[i]); } printf("前序遍历为:"); pre_order_tree(tree); printf("\n"); printf("中序遍历为:"); in_order_tree(tree); printf("\n"); printf("后序遍历为:"); post_order_tree(tree); printf("\n"); printf("删除10\n"); bsNode *dele=create_node(10,NULL,NULL,NULL); tree=dele_node(tree,dele); printf("前序遍历为:"); pre_order_tree(tree); printf("\n"); printf("中序遍历为:"); in_order_tree(tree); printf("\n"); printf("后序遍历为:"); post_order_tree(tree); printf("\n");
结果截图
- 二叉查找树(c语言实现)
- 二叉查找树C语言实现
- 二叉查找树c语言实现
- 二叉查找树C语言实现
- C语言实现二叉查找树
- 二叉查找树(C语言实现 )
- 二叉查找树的C语言实现
- 实现二叉查找树 -- C语言
- C语言实现二叉查找树
- 二叉查找树的C语言实现
- 数据结构:二叉查找树(C语言实现)
- c语言实现二叉查找树
- 二叉查找树实现(C语言版本)
- AVL平衡二叉查找树实现(C语言版本)
- 二叉查找树(BST)及其C语言实现
- 基于c语言实现的二叉查找树
- 二叉查找树的C语言实现(一)
- 二叉查找树的C语言实现(二)
- 浅析 java中 Int 与 String 互相转换问题
- bzoj 1187: [HNOI2007]神奇游乐园
- 设计模式六大原则
- LNMP相关软件安装目录
- 2016蓝桥杯省赛C/C++B组7题剪邮票 DFS枚举组合情况BFS判联通
- C语言实现二叉查找树
- IOS开发之如何开发出更好的应用
- SapJco配置方式
- java中compareTo和compare方法之比较
- iOS应用获取当前设备连接的wifi的名字
- FreeRTOS内核配置说明
- Android_Class_Activity
- 【BZOJ1055】[HAOI2008]玩具取名【区间DP】【状压】
- Joint Bilateral Filtering 双边滤波