二叉树:(1)每个结点都不大于2;(2)每个结点的孩子结点次序都不能颠倒。
满二叉树:深度为k的且有2^k-1个结点的二叉树
完全二叉树:深度为k,结点树为n的二叉树,如果其中结点1~n的位置序号分别与满二叉树的结点1~n的序号一一对应,则为完全二叉树。
满二叉树必为完全二叉树,完全二叉树不一定是满二叉树
二叉树的性质:
(1)在二叉树的第i层上之多有2^(i-1)结点
(2)深度为k的二叉树之多有2^k-1个结点
(3)对任意二叉树T,若叶子结点(度为0)的数为n0,而其度为2的结点数为n2,则n0=n2+1
(4)具有n的结点的完全二叉树的深度为(log2n)向下取整加1
(5)对于具有n个结点的完全二叉树,如果按照从上到下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号,
则对于任意的序号为i的结点有:
1.如果i=1,则序号为i的结点是跟结点,无双亲结点;如果i>1,则序号为i的结点的双亲结点i/2向下取整
2.如果2*i > n,则序号为i的结点无右孩子,如果2*i <= n,则序号为i的结点的左孩子结点的序号为2*i
3.如果2*i+1 > n,则序号为i的结点无右孩子,如果2*i+1 <= n,则序号为i的结点的右孩子结点的序号为2*i+1
满二叉树:深度为k的且有2^k-1个结点的二叉树
完全二叉树:深度为k,结点树为n的二叉树,如果其中结点1~n的位置序号分别与满二叉树的结点1~n的序号一一对应,则为完全二叉树。
满二叉树必为完全二叉树,完全二叉树不一定是满二叉树
二叉树的性质:
(1)在二叉树的第i层上之多有2^(i-1)结点
(2)深度为k的二叉树之多有2^k-1个结点
(3)对任意二叉树T,若叶子结点(度为0)的数为n0,而其度为2的结点数为n2,则n0=n2+1
(4)具有n的结点的完全二叉树的深度为(log2n)向下取整加1
(5)对于具有n个结点的完全二叉树,如果按照从上到下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号,
则对于任意的序号为i的结点有:
1.如果i=1,则序号为i的结点是跟结点,无双亲结点;如果i>1,则序号为i的结点的双亲结点i/2向下取整
2.如果2*i > n,则序号为i的结点无右孩子,如果2*i <= n,则序号为i的结点的左孩子结点的序号为2*i
3.如果2*i+1 > n,则序号为i的结点无右孩子,如果2*i+1 <= n,则序号为i的结点的右孩子结点的序号为2*i+1
#ifndef TreeHead_h__
#define TreeHead_h__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
typedef struct _BTree
{
char data;
struct _BTree *lChild;
struct _BTree *rChild;
}BTreeNode;
/************************************************************************/
/* */
/* 二叉树的基本操作---销毁、创建、判断是否为空 */
/* */
/************************************************************************/
//销毁一棵树
void DestroyBTree(BTreeNode **BTNode);
void DestroyBTree_Quene(BTreeNode **BTNode);
//创建一棵树
void CreateBTree(BTreeNode **BTNode);
//判断树是否为空
bool BTreeEmpty(BTreeNode *BTNode);
//删除左子树
void DeleteLeftTree(BTreeNode ** BTNode);
//删除右子树
void DeleteRightTree(BTreeNode **BTNode);
//输出树中的叶子结点
void PreOrderLeafNode(BTreeNode *BTNode);
/************************************************************************/
/* */
/* 根据遍历结果重新构建二叉树---前序和中序、后序和中序 */
/* */
/************************************************************************/
//根据先序和中序构建二叉树
BTreeNode *CreateTreeBy_PreMid(char *prestr, char *midstr);//OK
/************************************************************************/
/* */
/* 二叉树的遍历---递归和非递归 */
/* */
/************************************************************************/
//树的递归遍历
void PreOrderTraverse(BTreeNode *BTNode);
void InOrderTraverse(BTreeNode *BTNode);
void PostOrderTraverse(BTreeNode *BTNode);
//树的非递归遍历
void PreOrder(BTreeNode *BTNode);
void InOrder(BTreeNode *BTNode);
void PostOrder(BTreeNode *BTNode);
//层序遍历二叉树
void LayerOrder(BTreeNode *BTNode);
/************************************************************************/
/* */
/* 判断二叉树的属性---高度、结点个数、叶子结点个数 */
/* */
/************************************************************************/
//返回树的深度
int BTreeDepth(BTreeNode *BTNode);
//统计叶子结点的数目
int LeafCount(BTreeNode *BTNode);
//统计叶子结点数目的递归算法
int LeafCount_CUR(BTreeNode *BTNode);
//得到二叉树结点的个数
int GetBTreeLeafCount(BTreeNode *BTNode);
/************************************************************************/
/* */
/* 根据条件返回结点---值、结点 */
/* */
/************************************************************************/
//求二叉树中结点x的双亲结点
BTreeNode *Find_Parent(BTreeNode *BTNode, BTreeNode *node);
//返回节点x的左孩子,若结点无左孩子或者x不在树中,返回NULL
BTreeNode *LeftChild(BTreeNode *BTNode, BTreeNode *node);
//返回结点x的右孩子,若结点无右孩子或者x不在书中,返回NULL
BTreeNode *RightChild(BTreeNode *BTNode, BTreeNode *node);
//查找结点
BTreeNode *SearchNode(BTreeNode *BTNode, char value);
//给树的节点old赋值为new
void Assign(BTreeNode *BTNode, BTreeNode *Search, int newvalue);
/************************************************************************/
/* */
/* 判断二叉树的状态---相等、满二叉树、平衡二叉树、完全二叉树 */
/* */
/************************************************************************/
//判断两二叉树是否相等
bool IsEqual(BTreeNode *BTree1, BTreeNode *BTree2);
//判断二叉树是否为满二叉树
bool IsFullBTree(BTreeNode *BTNode);
//判断二叉树是否为完全二叉树
bool IsCompleteBTree(BTreeNode *BTNode);
//判断二叉树是否为平衡二叉树
bool IsBalanceBTree(BTreeNode *BTNode);
/************************************************************************/
/* */
/* 二叉树的其他操作 */
/* */
/************************************************************************/
//交换二叉树的左右子女
void ExchangeChild(BTreeNode **BTNode);//OK
#endif // TreeHead_h__
#include <stack> #include <queue> #include "TreeHead.h" //销毁一棵树 void DestroyBTree(BTreeNode **BTNode) { if ((*BTNode) != NULL) { DestroyBTree(&(*BTNode)->lChild); DestroyBTree(&(*BTNode)->rChild); free((*BTNode)); BTNode = NULL; } } //二叉树的非递归销毁方式 /************************************************************************/ /* 采用层序遍历的思想,销毁 */ /************************************************************************/ void DestroyBTree_Quene(BTreeNode **BTNode) { std::queue<BTreeNode *> queueBTree; BTreeNode *TempNode = NULL; if ((*BTNode) == NULL) { return; } TempNode = *BTNode; queueBTree.push(TempNode); while(!queueBTree.empty()) { TempNode = queueBTree.front(); queueBTree.pop(); if (TempNode->lChild != NULL) { queueBTree.push(TempNode->lChild); } if (TempNode->rChild != NULL) { queueBTree.push(TempNode->rChild); } free(TempNode); } } //创建一棵树 void CreateBTree(BTreeNode **BTNode) { char ch; scanf("%c", &ch); if ('#' == ch) { *BTNode = NULL; } else { (*BTNode) = (BTreeNode *)malloc(sizeof(BTreeNode)); (*BTNode)->data = ch; CreateBTree(&(*BTNode)->lChild); CreateBTree(&(*BTNode)->rChild); } } //判断树是否为空 bool BTreeEmpty(BTreeNode *BTNode) { if (BTNode == NULL) { return true; } else { return false; } } //求二叉树中结点x的双亲结点 BTreeNode *Find_Parent(BTreeNode *BTNode, BTreeNode *node) { BTreeNode *Temp = NULL; if (NULL == BTNode || node == BTNode->lChild || node == BTNode->rChild) { return BTNode; } Temp = Find_Parent(BTNode->lChild, node); if (NULL == Temp) { Temp = Find_Parent(BTNode->rChild, node); } return Temp; } //返回节点x的左孩子,若结点无左孩子或者x不在树中,返回NULL BTreeNode *LeftChild(BTreeNode *BTNode, BTreeNode *node) { BTreeNode *Result = NULL; if (BTNode != NULL) { if(BTNode->lChild != NULL && BTNode->lChild == node || BTNode->rChild == node) { Result = node->lChild; } else { LeftChild(BTNode->lChild, node); LeftChild(BTNode->rChild, node); } } return Result; } //返回结点x的右孩子,若结点无右孩子或者x不在书中,返回NULL BTreeNode *RightChild(BTreeNode *BTNode, BTreeNode *node) { BTreeNode *Result = NULL; if (NULL != BTNode) { if (NULL != BTNode && BTNode->lChild == node || node == BTNode->rChild) { Result = BTNode->lChild->rChild; } else { RightChild(BTNode->lChild, node); RightChild(BTNode->rChild, node); } } return Result; } //返回树的深度 int BTreeDepth(BTreeNode *BTNode) { int hLeft = 0; int hRight = 0; int max = 0; if (NULL != BTNode) { hLeft = BTreeDepth(BTNode->lChild); hRight = BTreeDepth(BTNode->rChild); max = hLeft > hRight ? hLeft : hRight; return (max+1); } else { return 0; } } //给树的节点old赋值为new void Assign(BTreeNode *BTNode, BTreeNode *Search, int newvalue) { if (NULL == BTNode || NULL == Search) { return; } if (NULL != BTNode) { if (NULL != BTNode && BTNode == Search) { BTNode->data = newvalue; } else { Assign(BTNode->lChild, Search, newvalue); Assign(BTNode->rChild, Search, newvalue); } } } //树的递归遍历 void PreOrderTraverse(BTreeNode *BTNode) { if (NULL != BTNode) { printf("%c-", BTNode->data); PreOrderTraverse(BTNode->lChild); PreOrderTraverse(BTNode->rChild); } } void InOrderTraverse(BTreeNode *BTNode) { if (NULL != BTNode) { InOrderTraverse(BTNode->lChild); printf("%c-", BTNode->data); InOrderTraverse(BTNode->rChild); } } void PostOrderTraverse(BTreeNode *BTNode) { if (NULL != BTNode) { PostOrderTraverse(BTNode->lChild); PostOrderTraverse(BTNode->rChild); printf("%c-", BTNode->data); } } //树的非递归遍历 /************************************************************************/ /*从跟结点开始,只要当前结点存在或者栈不空,就重复下面操作 */ /*(1)如果当前结点存在,则进栈并遍历左子树 */ /*(2)否则推占并访问,然后遍历右子树 */ /************************************************************************/ //借助栈,在打印当前节点后分别记录其右、左孩子 void PreOrder(BTreeNode *BTNode) { BTreeNode *TempTree = BTNode; std::stack<BTreeNode *> stackBTree; printf("非递归前序遍历为:"); while (NULL != TempTree || !stackBTree.empty()) { while (NULL != TempTree) { printf("%c-", TempTree->data); stackBTree.push(TempTree); TempTree = TempTree->lChild; } TempTree = stackBTree.top(); stackBTree.pop(); TempTree = TempTree->rChild; } printf("\b \n"); } //1.使用栈进行回溯 //2.每打印完一个节点,要对其右孩子做处理 //3.每个节点都需要不断找到最左边的孩子进行打印 void InOrder(BTreeNode *BTNode) { BTreeNode *TempTree = BTNode; std::stack<BTreeNode *> stackBTree; printf("非递归中序遍历为:"); while (NULL != TempTree || !stackBTree.empty()) { while (NULL != TempTree) { stackBTree.push(TempTree); TempTree = TempTree->lChild; } TempTree = stackBTree.top(); printf("%c-", TempTree->data); stackBTree.pop(); TempTree = TempTree->rChild; } printf("\b \n"); } void PostOrder(BTreeNode *BTNode) { BTreeNode *TempBTree = BTNode; BTreeNode *TempFlag = NULL; std::stack<BTreeNode *> stackBTree; printf("非递归后序遍历为:"); while (NULL != TempBTree || !stackBTree.empty()) { while (NULL != TempBTree) { stackBTree.push(TempBTree); TempBTree = TempBTree->lChild; } if(!stackBTree.empty()) { TempBTree = stackBTree.top(); if ((NULL == TempBTree->rChild) || (TempFlag == TempBTree->rChild)) { printf("%c-", TempBTree->data); TempFlag = TempBTree; stackBTree.pop(); TempBTree = NULL; } else { TempBTree = TempBTree->rChild; } } } printf("\b \n"); } //输出树中的叶子结点 /***********************************************************************************/ /* 输出叶子结点可以用三种遍历方法中任意一中实现,只需要在输出时判断左右孩子是否为空*/ /***********************************************************************************/ void PreOrderLeafNode(BTreeNode *BTNode) { printf("叶子结点为:"); if (NULL != BTNode) { if (NULL == BTNode->lChild && NULL == BTNode->rChild) { printf("%c-", BTNode->data); } PreOrderLeafNode(BTNode->lChild); PreOrderLeafNode(BTNode->rChild); } printf("\b \n"); } //统计叶子结点的数目 /***************************************************************************************/ /* 统计叶子结点数目可以用三种遍历方法中任意一中实现,只需要在输出时判断左右孩子是否为空*/ /***************************************************************************************/ int LeafCount(BTreeNode *BTNode) { int leafcount = 0; if (NULL != BTNode) { if (NULL == BTNode->lChild && NULL == BTNode->rChild) { leafcount++; } LeafCount(BTNode->lChild); LeafCount(BTNode->rChild); } return leafcount; } //得到二叉树结点的个数 int GetBTreeLeafCount(BTreeNode *BTNode) { //1+left+right if(NULL == BTNode) { return 0; } else { return (1+GetBTreeLeafCount(BTNode->lChild)+GetBTreeLeafCount(BTNode->rChild)); } } //统计叶子结点数目的递归算法 /*如果根结点为空,则返回0 如果根结点的左右子树为空,返回1 否则返回左右子树的和*/ int LeafCount_CUR(BTreeNode *BTNode) { int leafcount = 0; if (NULL == BTNode) { leafcount = 0; } else if ((NULL == BTNode->lChild) && (NULL == BTNode->rChild)) { leafcount = 1; } else { leafcount = LeafCount_CUR(BTNode->lChild) + LeafCount_CUR(BTNode->rChild); } return leafcount; } //判断两二叉树是否相等 bool IsEqual(BTreeNode *BTree1, BTreeNode *BTree2) { bool equalLeft, equalRight; if (NULL == BTree1 && NULL == BTree2) { return true; } else if (NULL == BTree1 || NULL == BTree2) { return false; } else { equalLeft = IsEqual(BTree1->lChild, BTree1->lChild); equalRight = IsEqual(BTree2->rChild, BTree2->rChild); return(equalLeft && equalRight); } } //求从二叉树跟结点到r结点之间的路径 void Path(BTreeNode *BTNode, BTreeNode *GoalNode) { BTreeNode *Temp1 = BTNode; BTreeNode *Temp2 = NULL; std::stack<BTreeNode *> stackBtree; while (Temp1 != NULL || !stackBtree.empty()) { while(Temp1 != NULL) { stackBtree.push(Temp1); Temp1 = Temp1->lChild; } if (!stackBtree.empty()) { Temp1 = stackBtree.top(); if (Temp1->rChild == NULL || Temp1->rChild == Temp2) { if (Temp2 == GoalNode) { for (int i = 1; i < stackBtree.size(); i++) { printf("%c-", stackBtree.top()); stackBtree.pop(); } return; } else { Temp2 = Temp1; stackBtree.pop(); Temp1 = NULL; } } else { Temp1 = Temp1->rChild; } } } } //层序遍历二叉树 /* (1)若二叉树为空,则直接返回 (2)将二叉树的根节点放到队列 (3)若队列非空,则执行下面操作: 队头元素出队,并访问 若该结点的左孩子非空,则将该结点的左孩子如队列 若该节点的右孩子非空,则将该结点的右孩子入对列 */ void LayerOrder(BTreeNode *BTNode) { BTreeNode *Temp = NULL; std::queue<BTreeNode *> queueBTree; printf("树的层序遍历为:"); if (NULL == BTNode) { return; } queueBTree.push(BTNode); while(!queueBTree.empty()) { Temp = queueBTree.front(); printf("%c-", Temp->data); if (Temp->lChild != NULL) { queueBTree.push(Temp->lChild); } if (Temp->rChild != NULL) { queueBTree.push(Temp->rChild); } queueBTree.pop(); } printf("\b \n"); } //交换二叉树的左右子女 void ExchangeChild(BTreeNode **BTNode) { if ((*BTNode) != NULL) { BTreeNode *Temp = NULL; if ((*BTNode)->lChild != NULL || (*BTNode)->rChild != NULL) { Temp = (*BTNode)->lChild; (*BTNode)->lChild = (*BTNode)->rChild; (*BTNode)->rChild = Temp; ExchangeChild(&(*BTNode)->lChild); ExchangeChild(&(*BTNode)->rChild); } } } //删除左子树 void DeleteLeftTree(BTreeNode ** BTNode) { if (NULL == (*BTNode)) { return; } else { DeleteLeftTree(&(*BTNode)->lChild); (*BTNode)->lChild = NULL; } } //删除右子树 void DeleteRightTree(BTreeNode **BTNode) { if (NULL == (*BTNode)) { return; } else { DeleteRightTree(&(*BTNode)->rChild); (*BTNode)->rChild = NULL; } } //查找结点 BTreeNode *SearchNode(BTreeNode *BTNode, char value) { BTreeNode *Result = NULL; if (NULL == BTNode) { return NULL; } else if(value == BTNode->data) { return BTNode; } else { Result = SearchNode(BTNode->lChild, value); if (NULL != Result) { return Result; } else { return SearchNode(BTNode->rChild, value); } } } //判断二叉树是否为满二叉树 bool IsFullBTree(BTreeNode *BTNode) { int high = 0; bool Result = false; if (NULL != BTNode) { high = BTreeDepth(BTNode); } if(pow(2, high)-1 == GetBTreeLeafCount(BTNode)) { Result = true; } return Result; } //判断二叉树是否为完全二叉树 bool IsCompleteBTree(BTreeNode *BTNode) { //层序遍历一个二叉树,一旦找到一个不含有子节点或者只含有一个左孩子节点之后,那么 //后续的所有节点都必须是叶子节点,否则该树就不是完全二叉树 std::queue<BTreeNode *> queueBTree; if (NULL != BTNode) { queueBTree.push(BTNode); BTreeNode *Cur = NULL; bool bFlag = false; while (!queueBTree.empty()) { Cur = queueBTree.front(); queueBTree.pop(); if (Cur != NULL) { if (bFlag != false) { return false; } queueBTree.push(Cur->lChild); queueBTree.push(Cur->rChild); } else { bFlag = true; } } return true; } return true; } //判断二叉树是否为平衡二叉树 bool IsBalanceBTree(BTreeNode *BTNode) { if(NULL == BTNode) { return false; } int high_left = BTreeDepth(BTNode->lChild); int high_right = BTreeDepth(BTNode->rChild); if (abs((high_left-high_right) <= 1)) { return true; } return false; } //根据先序和中序构建二叉树 BTreeNode *CreateTreeBy_PreMid(char *prestr, char *midstr) { int length = strlen(prestr); if (NULL == prestr || NULL == midstr || length <= 0) { return NULL; } char RootValue = prestr[0];//根结点 //建立跟结点 BTreeNode *Root = (BTreeNode *)malloc(sizeof(BTreeNode)); Root->data = RootValue; Root->lChild = Root->rChild = NULL; int length_left = 0; int length_right = 0; int i = 0; while (i < length && midstr[i] != RootValue) { i++; } length_left = i; length_right = length - length_left - 1; if (length_left > 0) { Root->lChild = CreateTreeBy_PreMid(prestr+1, midstr); } if (length_left > 0) { Root->rChild = CreateTreeBy_PreMid(prestr+length-length_right, midstr+length-length_right); } return Root; }
//测试
#include "TreeHead.h" /************************************************************************/ /* A B D # F # # # C E # # # */ /* A B C # # D E # # F # # G H # I # # J # # */ /************************************************************************/ int main(void) { BTreeNode *Root = NULL; BTreeNode *Test = NULL; /************************************************************************/ /* 二叉树的创建与遍历 */ /************************************************************************/ //创建二叉树 printf("请输入要创建树的结点:"); CreateBTree(&Root); //统计二叉树结点的个数 printf("二叉树结点的总个数为:%d\n", GetBTreeLeafCount(Root)); //前序递归遍历 printf("该树的递归前序遍历为:"); PreOrderTraverse(Root); printf("\b \n"); //中序递归遍历 printf("该树的递归中序遍历为:"); InOrderTraverse(Root); printf("\b \n"); //后续递归遍历 printf("该树的递归后序遍历为:"); PostOrderTraverse(Root); printf("\b \n"); //二叉树的深度测试 printf("树的深度为:%d\n", BTreeDepth(Root)); //非递归的前、中、后续遍历 PreOrder(Root); InOrder(Root); PostOrder(Root); LayerOrder(Root); //交换后左右子树的输出 printf("左右子树交换后为:\n"); ExchangeChild(&Root); //销毁树 //DestroyBTree(&Root); //删除左右子树 // DeleteLeftTree(&Root); // DeleteRightTree(&Root); PreOrder(Root); InOrder(Root); PostOrder(Root); LayerOrder(Root); /************************************************************************/ /* 根据给定值查找结点、修改结点的值 */ /************************************************************************/ BTreeNode *Result = NULL; BTreeNode *Res = NULL; Result = SearchNode(Root, 'A'); std::cout << "查找到的结点为" << Result->data <<std::endl; Assign(Root, Result, 'O'); PreOrder(Root); InOrder(Root); PostOrder(Root); LayerOrder(Root); // // Res = LeftChild(Root, Result); /* printf("结点的左孩子为%c\n", Res->data);*/ /************************************************************************/ /* 判断二叉树是否为空、相等、平衡、满二叉 */ /************************************************************************/ //二叉树是否为空 if(BTreeEmpty(Root)) { printf("该二叉树是空的\n"); } else { printf("该二叉树非空\n"); } //判断二叉树是否相等 if(IsEqual(Root, Test)) { printf("两棵树相等\n"); } else { printf("两棵树不相等\n"); } //判断二叉树是否为满二叉树 if (IsFullBTree(Root) == true) { printf("是满二叉树\n"); } else { printf("不是满二叉树\n"); } //判断二叉树是否为完全二叉树 if (IsCompleteBTree(Root) == true) { printf("是完全二叉树\n"); } else { printf("不是完全二叉树\n"); } //二叉树是否是平衡二叉树 if (IsBalanceBTree(Root) == true) { printf("是平衡二叉树\n"); } else { printf("不是平衡二叉树\n"); } /************************************************************************/ /* 根据给定的序列还原二叉树 */ /************************************************************************/ std::cout<<"----------根据给定的序列还原二叉树----------"<<std::endl; BTreeNode *Node_1 = NULL; BTreeNode *Node_2 = NULL; char preStr[] = "ABDECF"; char midStr[] = "DBEAFC"; char posStr[] = "DEBFCA"; Node_1 = CreateTreeBy_PreMid(preStr, midStr); PostOrder(Node_1); LayerOrder(Node_1); Node_2 = CreateTreeBy_MidPos(midStr, posStr); PreOrder(Node_2); LayerOrder(Node_2); return 0; } /* 线索二叉树: 可以得到结点在遍历序列中前驱和后继的信息 方法:利用二叉链表中的空链域,将遍历过程中结点的前驱、后继信息保存下来 若结点有左孩子,则其lChild域指向其左孩子,否则lChild域指向其前驱结点 若结点有右孩子,则其rChild域指向其有孩子,否则rChild域指向其后继结点 树的遍历: 树的先跟遍历<<----------->>二叉树的前序遍历 树的后跟遍历<<----------->>二叉树的中序遍历 */