1.初识树
首先来看树的几个很重要的概念。节点的度是这个节点所拥有的子树的个数,如果度为0那这个节点称为叶子节点。树的深度是树中所有节点的最大层数,树的度是各节点度的最大值。如果树的各节点的左右子树从左到右是有序的则为有序树,反之为无序树。树的遍历分为前序、中序和后序,树也有很多类型,下面是一些常见的树类型。
二叉树:二叉树的每个节点的子节点不会超过2个,而且它是一颗有序树,左右子树不能交换,若交换左右子树将变为另一颗不同的树。
满二叉树:在二叉树中,如果所有非叶子节点都有2个子节点,而且所有叶子节点都在同一层上(即所有叶子节点到根节点的路径相同)则是一颗满二叉树。它的节点的度只有0和2。
完全二叉树:可以将它看成是把满二叉树从右向左从下往上减去叶子节点。它的特点是所有叶子节点只能在最下层或次下层,且最下层的叶子节点都在左边。深度为n的完全二叉树在n-1层一定是满二叉树。
二叉排序树:也称为二叉查找树,特点是左子树的所有节点均小于根节点,右子树的所有节点均小于根节点且一个节点的左子树与右子树均为二叉排序树,因此二叉排序树中没有相等的树。
红黑树:它的数据结构是值、左孩子节点、右孩子节点、颜色和父节点。它不为空时,所有节点为红或黑颜色的节点且根节点是黑色,所有为null的节点为叶子节点且颜色为黑色,所有红节点的子节点都为黑色,从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。
平衡二叉树:它是在二叉排序树的基础上增加了一个特点,它的左右子树的高度之差不能超过1,如果由于插入或删除打破了这个规则则需要进行旋转恢复平衡。
2.二叉树的性质
二叉树有如下一些主要的性质。一颗二叉树第i层最多有2^(i-1)个节点;一颗深度为k的二叉树中,最多有2^k-1个节点;对于一颗非空的二叉树,如果叶子节点为数为n0,度为2的节点树为n2,则有k=j+1。设这颗二叉树的 总节点为n,它等于子节点分别为0、1、2的总和,这样可以得到一个等式n=n1+n2+n3。接下来要利用二叉树中的分支,假设分支数为m,除了根节点没有父节点外其余所有节点都有父节点也就是有“分支”,对于有2个子节点的节点,每一个这样的节点表示有2个分支,同理一个子节点的节点代表的是有一个分支。这样可以得到另两个等式m=n-1,m=n1+2n2。通过这两个等式可以得到n0=n2+1;
一颗有n个节点的完全二叉树深度为k,则k为lbn+1,由完全二叉树的定义可知深度为k的节点数范围是2^(k-1)<=n<2^k-1,对该不等式取对数可得到lbn<k<=lbn+1,故k为lbn+1。如果对具有n个节点的完全二叉树按照从左到右从上到下的顺序进行编号,对于其中任意一个序号为k的节点,它不为1时父节点的序号为k/2。如果2k<=n,则它的左孩子节点序号为2k,如果2k>n则该节点为左孩子节点。如果2k+1<=n,则右孩子节点为2k+1,而2k+1>n时则该节点无右孩子节点。
3.二叉树的遍历
struct BinaryTree{ int value; BinaryTree* leftTree; BinaryTree* rightTree; }; //前序遍历 void FrontTraverse(BinaryTree* root) { if(root!=NULL) { if(root->leftTree) FrontTraverse(root->leftTree); printf("%d ",root->value); if(root->rightTree) FrontTraverse(root->rightTree); } } //中序遍历 void MiddleTraverse(BinaryTree* root) { if(root!=NULL) { printf("%d ",root->value); if(root->leftTree) FrontTraverse(root->leftTree); if(root->rightTree) FrontTraverse(root->rightTree); } } //后序遍历 void BehindTraverse(BinaryTree* root) { if(root!=NULL) { if(root->leftTree) FrontTraverse(root->leftTree); if(root->rightTree) FrontTraverse(root->rightTree); printf("%d ",root->value); } }
4.二叉树的基本操作
#include<stdio.h> #include<stdlib.h> struct BinaryTree{ int value; BinaryTree* leftTree; BinaryTree* rightTree; BinaryTree() { leftTree=NULL; rightTree=NULL; } }; //初始化二叉树 void InitBiTree(BinaryTree* root) { BinaryTree* node1=new BinaryTree(); BinaryTree* node2=new BinaryTree(); BinaryTree* node3=new BinaryTree(); BinaryTree* node4=new BinaryTree(); BinaryTree* node5=new BinaryTree(); node1->value=4; node2->value=12; node3->value=5; node4->value=10; node5->value=15; root->leftTree=node1; root->rightTree=node2; node1->rightTree=node3; node2->leftTree=node4; node2->rightTree=node5; } //中序遍历 void MiddleTraverse(BinaryTree* root) { if(root==NULL) return; if(root->leftTree) MiddleTraverse(root->leftTree); printf("%d ",root->value); if(root->rightTree) MiddleTraverse(root->rightTree); } //新增二叉树的节点 void AddBiTree(BinaryTree* root,int key) { if(root==NULL) return; BinaryTree* keyNode=new BinaryTree(); keyNode->value=key; BinaryTree* node=root; BinaryTree* prevNode; if(key>node->value) { while(node&&node->value<key) { prevNode=node; node=node->rightTree; } if(node==NULL) //node节点此时有可能是NULL prevNode->rightTree=keyNode; else { //现在node的value是比key大的 prevNode->rightTree=keyNode; keyNode->rightTree=node; } } else { while(node&&node->value>key) { prevNode=node; node=node->leftTree; } if(node==NULL) //node节点此时有可能是NULL prevNode->leftTree=keyNode; else { //现在node的value是比key小的 prevNode->leftTree=keyNode; keyNode->leftTree=node; } } } //查找一个节点,得到这个节点的引用以及父节点 void QueryBiTree(BinaryTree *root,int key,BinaryTree **keyNode,BinaryTree **parentNode) { if(root==NULL) return; if(root->value==key) { *keyNode=root; return; } BinaryTree* node=root; if(root->leftTree&&root->leftTree->value==key) { *keyNode=root->leftTree; *parentNode=root; return; } if(root->rightTree && root->rightTree->value==key) { *keyNode=root->rightTree; *parentNode=root; return; } if(root->value>key) QueryBiTree(root->leftTree,key,keyNode,parentNode); if(root->value<key) QueryBiTree(root->rightTree,key,keyNode,parentNode); } //删除一个节点 void DeleteBiTree(BinaryTree* root,int key) { if(root==NULL) return; //首先找到这个节点 bool isLeft=false; BinaryTree* keyNode=NULL; BinaryTree* parentNode=NULL; QueryBiTree(root,key,&keyNode,&parentNode); if(parentNode&&parentNode->leftTree==keyNode) isLeft=true; //1.如果该节点有右子树,寻找右子树的最左节点,这个节点也可能是根节点。 if(keyNode->rightTree) { BinaryTree* leftNode=keyNode->rightTree; //如果被删除节点的右孩子节点的左节点为空 if(leftNode->leftTree==NULL) { //将右孩子节点的值赋给keyNode并删除keyNode->rightNode; keyNode->value=keyNode->rightTree->value; keyNode->rightTree=keyNode->rightTree->rightTree; } else { BinaryTree* parentLeftNode; //不停的寻找右子树的最左节点 while(leftNode->leftTree) { //leftNode的父节点 parentLeftNode=leftNode; leftNode=leftNode->leftTree; } //此时leftNode则是右子树里的最左节点,然后将这个节点的值赋给keyNode keyNode->value=leftNode->value; parentLeftNode->leftTree=leftNode->rightTree; } delete leftNode; return; } //2.如果该节点只有左子树,这里要分情况讨论,因为要删除的节点有可能是根节点 if(keyNode->leftTree&&keyNode->rightTree==NULL) { //如果此时删除的节点是根节点 if(parentNode==NULL) root=root->leftTree; else { //如果被删除节点的右子树为空,则直接去掉这个节点 if(isLeft) parentNode->leftTree=keyNode->leftTree; else parentNode->rightTree=keyNode->leftTree; delete keyNode; } return; } //3.如果该节点本身是叶子节点 if(keyNode->leftTree==NULL&&keyNode->rightTree==NULL) { //如果此时节点是根节点 if(keyNode==root) root=NULL; else { if(isLeft) parentNode->leftTree=NULL; else parentNode->leftTree=NULL; } delete keyNode; } } void main() { BinaryTree* root=new BinaryTree(); root->value=6; //初始化二叉树 InitBiTree(root); //新增节点9,5 AddBiTree(root,3); MiddleTraverse(root); printf("\n"); AddBiTree(root,9); MiddleTraverse(root); printf("\n"); //删除节点 //DeleteBiTree(root,3); //DeleteBiTree(root,4); //DeleteBiTree(root,5); //DeleteBiTree(root,6); //DeleteBiTree(root,9); DeleteBiTree(root,12); MiddleTraverse(root); printf("\n"); }
这是我自己写的关于二叉树的创建、新增、查找与删除的代码,如有错误还请各位员友指出!