二叉树的基本操作

来源:互联网 发布:linux基础面试题 编辑:程序博客网 时间:2024/06/01 13:40
二叉树:(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
#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不在树中,返回NULLBTreeNode *LeftChild(BTreeNode *BTNode, BTreeNode *node);//返回结点x的右孩子,若结点无右孩子或者x不在书中,返回NULLBTreeNode *RightChild(BTreeNode *BTNode, BTreeNode *node);//查找结点BTreeNode *SearchNode(BTreeNode *BTNode, char value);//给树的节点old赋值为newvoid 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不在树中,返回NULLBTreeNode *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不在书中,返回NULLBTreeNode *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赋值为newvoid 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+rightif(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域指向其后继结点树的遍历:树的先跟遍历<<----------->>二叉树的前序遍历树的后跟遍历<<----------->>二叉树的中序遍历*/




0 0
原创粉丝点击