二叉树的详细实现 (C++)
Posted windsun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的详细实现 (C++)相关的知识,希望对你有一定的参考价值。
二叉树的定义
以递归形式给出的:一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。二又树的特点是每个结点最多有两个子女,分别称为该结点的左子女和右子女。在二又树中不存在度大于2的结点,并且二又树的子树有左、右之分,其子树的次序不能颠倒。二又树是分支数最大不超过2的有根有序树。它可能有5种不同的形态。
二叉树的性质
二叉树的数组存储方式
遇到空子树,应在编号时假定有此子树进行编号,而在顺序存储时当作有此子树那样把位置留出来。这样才能反映二叉树结点之间的相互关系,由其存储位置找到它的父结点、子女、兄弟结点的位置。但这样做有可能会消耗大量的存储空间。例如:单支二叉树,会浪费很多空间。
如果根节点编号是从1开始有有以下结论:
中间节点一定在倒数第二层,最后一个节点的数就是总节点的个数,总结点数除2就是中间节点的数的个数,父节点的节点数*2<总节点个数,当前节点一定有两个孩子,如果=就只有一个孩子,如果<就没有一个孩子。
二叉树的链表存储表示
二叉树结点类型的定义
1 template<typename T> 2 struct BinTreeNode 3 { 4 T data; //结点中存储的数据 5 BinTreeNode<T> *leftChild, *rightChild; //左子树和右子树 6 BinTreeNode() :leftChild(NULL), rightChild(NULL) {} //无参构造函数 7 BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) :data(x), leftChild(l), rightChild(r) {} //带默认值的有参构造参数 8 };
二叉树的基本框架
1 template<typename T> 2 class BinaryTree 3 { 4 public: 5 //构造函数 6 BinaryTree() :root(NULL) {} 7 //指定结束标志的构造函数 8 BinaryTree(T value) :RefValue(value), root(NULL) {} 9 //复制构造函数(前序遍历的应用) 10 BinaryTree(BinaryTree<T>& s) 11 { 12 root = Copy(s.getRoot()); 13 } 14 //判断两颗二叉树是否相等(前序遍历的应用) 15 bool operator==(BinaryTree<T>& s) 16 { 17 return (equal(this->getRoot(), s.getRoot())); 18 } 19 //析构函数 20 ~BinaryTree() { Destroy(root); } 21 //创建二叉树(使用广义表创建) 22 void CreateBinTree() { CreateBinTree(root); } 23 //创建二叉树(利用二叉树的前序遍历创建)(前序遍历的应用) 24 void CreateBinTree_PreOrder() { CreateBinTree_PreOrder(root); } 25 //二叉树中序遍历(递归) 26 void InOrder() { InOrder(root); } 27 //二叉树先序遍历(递归) 28 void PreOrder() { PreOrder(root); } 29 //二叉树先序遍历(非递归1) 30 void PreOrder_NoRecurve1() { PreOrder_NoRecurve1(root); } 31 //二叉树先序遍历(非递归2) 32 void PreOrder_NoRecurve2() { PreOrder_NoRecurve2(root); } 33 //二叉树后序遍历(递归) 34 void PostOrder() { PostOrder(root); } 35 //二叉树的层次遍历(非递归遍历) 36 void LevelOrder() { LevelOrder(root); } 37 //二叉树的中序遍历(非递归) 38 void InOrder_NoRecurve() { InOrder_NoRecurve(root); } 39 //计算二叉树的结点的个数(后序遍历的应用) 40 int Size() { return Size(root); } 41 //计算二叉树的高度(后序遍历的应用) 42 int Height() { return Height(root); } 43 //销毁函数 44 void Destroy() { Destroy(root); } 45 //返回current结点的父节点 46 BinTreeNode<T>* Parent(BinTreeNode<T>* current) 47 { 48 return (root == NULL || root == current) ? NULL : Parent(root, current); 49 } 50 //判断二叉树是否为空 51 bool Empty() { return (root == NULL) ? true : false; } 52 //返回current结点的左结点 53 BinTreeNode<T>* LeftChild(BinTreeNode<T>* current) 54 { 55 return (current != NULL) ? current->leftChild : NULL; 56 } 57 //返回current结点的右结点 58 BinTreeNode<T>* RightChild(BinTreeNode<T>* current) 59 { 60 return (current != NULL) ? current->rightChild : NULL; 61 } 62 //获取二叉树的根节点 63 BinTreeNode<T>* getRoot() const 64 { 65 return root; 66 } 67 //以广义表的形式输出二叉树(前序遍历的应用) 68 void PrintBinTree() { PrintBinTree(root); } 69 //二叉树的后序遍历(非递归) 70 void PostOrder_NoRecurve() { PostOrder_NoRecurve(root); } 71 72 protected: 73 //使用广义表创建二叉树函数,这里以“字符”创建二叉树,以‘#‘字符代表结束 74 void CreateBinTree(BinTreeNode<T>* &BT); 75 //二叉树的中序遍历 76 void InOrder(BinTreeNode<T> *&subTree); 77 //二叉树的先序遍历 78 void PreOrder(BinTreeNode<T> *&subTree); 79 //二叉树的后序遍历 80 void PostOrder(BinTreeNode<T> *&subTree); 81 //计算二叉树以subTree为根的结点的个数 82 int Size(BinTreeNode<T> *subTree) const; 83 //计算二叉数以subTree为根的结点的个数 84 int Height(BinTreeNode<T> *subTree); 85 //二叉树的销毁函数 86 void Destroy(BinTreeNode<T> *&subTree); 87 //从结点subTree开始,搜索结点current的父节点,找到返回父节点的地址,找不到返回NULL 88 BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current); 89 //复制构造函数调用的Copy函数,返回一个指针,给出一个以originNode为根的二叉树的副本 90 BinTreeNode<T>* Copy(BinTreeNode<T>* originNode); 91 //判断两颗二叉树是否相等 92 bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b); 93 //创建二叉树(利用已知的二叉树的前序遍历创建)用#表示空结点 94 void CreateBinTree_PreOrder(BinTreeNode<T>* &subTree); 95 //以广义表的形式输出二叉树 96 void PrintBinTree(BinTreeNode<T> *BT); 97 //二叉树先序遍历(非递归1) 98 void PreOrder_NoRecurve1(BinTreeNode<T> *p); 99 //二叉树先序遍历(非递归2) 100 void PreOrder_NoRecurve2(BinTreeNode<T> *p); 101 //二叉树的层次遍历(非递归遍历) 102 void LevelOrder(BinTreeNode<T> *p); 103 //二叉树的中序遍历(非递归) 104 void InOrder_NoRecurve(BinTreeNode<T>* p); 105 //二叉树的后序遍历(非递归) 106 void PostOrder(BinTreeNode<T>* p); 107 108 private: 109 BinTreeNode<T>* root; //根节点 110 T RefValue; //数据输入停止的标志,需要一个构造函数 111 };
二叉树的创建
1.使用广义表创建
从广义表A(B(D,E(G,)),C(,F))# 建立起来的二叉树。
算法基本思路:
1.若是字母(假定以字母作为结点的值),则表示是结点的值,为它建立一个新的结点,并把该结点作为左子女(当k=1)或右子女(当k=2)链接到其父结点上。
2.若是左括号"(",则表明子表的开始,将k置为1;若遇到的是右括号")",则表明子表结束。
3.若遇到的是逗号",",则表示以左子女为根的子树处理完毕,应接着处理以右子女为根的子树,将k置为2。如此处理每一个字符,直到读入结束符“#”为止。
在算法中使用了一个栈s,在进入子表之前将根结点指针进栈,以便括号内的子女链接之用。在子表处理结束时退栈。
1 //使用广义表创建二叉树函数,这里以“字符”创建二叉树,以‘#‘字符代表结束 2 void CreateBinTree(BinTreeNode<T>* &BT) 3 { 4 stack< BinTreeNode<T>* > s; 5 BT = NULL; 6 BinTreeNode<T> *p, *t; //p用来记住当前创建的节点,t用来记住栈顶的元素 7 int k; //k是处理左、右子树的标记 8 T ch; 9 cin >> ch; 10 11 while (ch != RefValue) 12 { 13 switch (ch) 14 { 15 case ‘(‘: //对(做处理 16 s.push(p); 17 k = 1; 18 break; 19 20 case ‘)‘: //对)做处理 21 s.pop(); 22 break; 23 24 case ‘,‘: //对,做处理 25 k = 2; 26 break; 27 28 default: 29 p = new BinTreeNode<T>(ch); //构造一个结点 30 if (BT == NULL) //如果头节点是空 31 { 32 BT = p; 33 } 34 else if (k == 1) //链入*t的左孩子 35 { 36 t = s.top(); 37 t->leftChild = p; 38 } 39 else //链入*t的右孩子 40 { 41 t = s.top(); 42 t->rightChild = p; 43 } 44 } 45 cin >> ch; 46 } 47 }
2.使用已知的二叉树的前序遍历创建
必须对应二又树结点前序遍历的顺序,并约定以输入序列中不可能出现的值作为空结点的值以结束递归,此值通过构造函数存放在RefValue中。例如用“#”或表示字符序列或正整数序列空结点。
前序遍历所得到的前序序列为ABC##DE#G##F###。
算法的基本思想是:
每读入一个值,就为它建立结点。该结点作为根结点,其地址通过函数的引用型参数subTree直接链接到作为实际参数的指针中。然后,分别对根的左、右子树递归地建立子树,直到读入“#”建立空子树递归结束。
1 //创建二叉树(利用已知的二叉树的前序遍历创建)用#表示空结点 2 void CreateBinTree_PreOrder(BinTreeNode<T>* &subTree) 3 { 4 T item; 5 if (cin >> item) 6 { 7 if (item != RefValue) 8 { 9 subTree = new BinTreeNode<T>(item); //构造结点 10 if (subTree == NULL) 11 { 12 cout << "空间分配错误!" << endl; 13 exit(1); 14 } 15 CreateBinTree_PreOrder(subTree->leftChild); //递归创建左子树 16 CreateBinTree_PreOrder(subTree->rightChild); //递归创建右子树 17 } 18 else 19 { 20 subTree == NULL; 21 } 22 } 23 }
二叉树的递归遍历
先序遍历:根->左->右
1 //二叉树的先序遍历 2 void PreOrder(BinTreeNode<T> *&subTree) 3 { 4 if (subTree != NULL) 5 { 6 cout << subTree->data << " "; 7 PreOrder(subTree->leftChild); 8 PreOrder(subTree->rightChild); 9 } 10 }
中序遍历:左->根->右
1 //二叉树的中序遍历 2 void InOrder(BinTreeNode<T> *&subTree) 3 { 4 if (subTree != NULL) 5 { 6 InOrder(subTree->leftChild); 7 cout << subTree->data << " "; 8 InOrder(subTree->rightChild); 9 } 10 }
后续遍历:左->右->根
1 //二叉树的后序遍历 2 void PostOrder(BinTreeNode<T> *&subTree) 3 { 4 if (subTree != NULL) 5 { 6 PostOrder(subTree->leftChild); 7 PostOrder(subTree->rightChild); 8 cout << subTree->data << " "; 9 } 10 }
二叉树的非递归遍历
先序遍历
为了把一个递归过程改为非递归过程,一般需要利用一个工作栈,记录遍历时的回退路径。
利用栈实现前序遍历的过程。每次访问一个结点后,在向左子树遍历下去之前,利用这个栈记录该结点的右子女(如果有的话)结点的地址,以便在左子树退回时可以直接从栈顶取得右子树的根结点,继续其右子树的前序遍历。
1 //二叉树先序遍历(非递归1) 2 void PreOrder_NoRecurve1(BinTreeNode<T> *p) 3 { 4 stack<BinTreeNode<T>*> S; 5 S.push(NULL); //最先push一个NULL,到最后一个结点没有左右子树时,栈里只有一个NULL了,令指针p指向这个NULL,再判断就会结束循环 6 while (p!=NULL) 7 { 8 cout << p->data << " "; 9 if(p->rightChild!=NULL) //预留右子树指针在栈中 10 { 11 S.push(p->rightChild); 12 } 13 14 if (p->leftChild!=NULL) //进左子树 15 { 16 p = p->leftChild; 17 } 18 else //左子树为空 19 { 20 p = S.top(); 21 S.pop(); 22 } 23 } 24 }
另一种前序遍历的方法。为了保证先左子树后右子树的顺序,在进栈时是先进右子女结点地址,后进左子女结点地址,出栈时正好相反。
1 //二叉树先序遍历(非递归2) 2 void PreOrder_NoRecurve2(BinTreeNode<T> *p) 3 { 4 stack<BinTreeNode<T>*> S; 5 BinTreeNode<T>* t; 6 S.push(p); //根节点进栈 7 while (!S.empty()) //当栈不为空 8 { 9 t = S.top(); //p先记住栈顶元素,然后栈顶出栈 10 S.pop(); 11 cout << t->data << " "; //访问元素 12 if (t->rightChild != NULL) //右孩子不为空,右孩子近栈 13 { 14 S.push(t->rightChild); 15 } 16 if (t->leftChild != NULL) //左孩子不为空,左孩子进栈 17 { 18 S.push(t->leftChild); 19 } 20 } 21 }
中序遍历
需要使用一个栈,以记录遍历过程中回退的路径。在一棵子树中首先访问的是中序下的第一个结点,它位于从根开始沿leftChild链走到最左下角的结点,该结点的leftChild指针为NULL。访问它的数据之后,再遍历该结点的右子树。此右子树又是二叉树,重复执行上面的过程,直到该子树遍历完。
如果某结点的右子树遍历完或右子树为空,说明以这个结点为根的二叉树遍历完,此时从栈中退出更上层的结点并访问它,再向它的右子树遍历下去。
1 //二叉树的中序遍历(非递归) 2 void InOrder_NoRecurve(BinTreeNode<T>* p) 3 { 4 stack<BinTreeNode<T>*> S; 5 do 6 { 7 while (p!=NULL) 8 { 9 S.push(p); 10 p = p->leftChild; 11 } 12 if (!S.empty()) 13 { 14 p = S.top(); 15 S.pop(); 16 cout << p->data << " "; 17 p = p->rightChild; 18 } 19 } 20 while (p!=NULL||!S.empty()); 21 }
后续遍历
后序遍历比前序和中序遍历的情况复杂。在遍历完左子树时还不能访问根结点,需要再遍历右子树。待右子树遍历完后才访问根结点。所以在栈工作记录中必须注明刚才是在左子树(L)还是在右子树(R)中。
在后序遍历中所用栈的结点定义:
1 //后续遍历(非递归)所用的注明左右的结点的类型 2 template<typename T> 3 struct stkNode 4 { 5 BinTreeNode<T> *ptr; //指向树结点的指针 6 enum tag { L, R }; //该结点退栈的标记 7 stkNode(BinTreeNode<T> *N = NULL) :ptr(N), tag(L) {} //带默认值的有参构造函数 8 };
算法思想:首先使用栈暂存根结点地址,再向左子树遍历下去,此时根结点的tag=L。当访问完左子树中结点并从左子树退回时,还要去遍历根的右子树,此时改根结点的tag=R。在从右子树中退出时才访问位于栈顶的根结点的值。
1 //二叉树的后序遍历(非递归) 2 void PostOrder(BinTreeNode<T>* p) 3 { 4 stack<stkNode<T>> S; //创建一个栈 5 stkNode<T> w; //创建一个注明左右类型的结点 6 do 7 { 8 while (p != NULL) //循环将左结点压栈 9 { 10 w.ptr = p; 11 w.tag = L; 12 S.push(w); 13 p = p->leftChild; 14 } 15 int flag = 1; //默认flag为1 16 while (flag&&S.empty()) 17 { 18 w = S.top(); //记住栈顶元素并出栈 19 S.pop(); 20 p = w.ptr; //并使p指向记住的栈顶元素中存储的结点 21 switch (w.tag) 22 { 23 case L: //若标记为左,就将标志改为右,再进栈 24 w.tag = R; 25 S.push(w); 26 flag = 0; //flag置为0 27 p = p->rightChild; 28 break; 29 case R: //若标记为右孩子 30 cout << p->data << " "; 31 break; 32 } 33 } 34 } 35 while (!S.empty()); 36 cout << endl; 37 }
层次遍历
按层次顺序访问二叉树的处理需要利用一个队列。在访问二又树的某一层结点时,把下一层结点指针预先记忆在队列中,利用队列安排逐层访问的次序。因此,每当访问一个结点时,将它的子女依次加到队列的队尾,然后再访问已在队列队头的结点。这样可以实现二又树结点的按层访问。
1 //二叉树的层次遍历(非递归遍历) 2 void LevelOrder(BinTreeNode<T> *p) 3 { 4 queue<BinTreeNode<T>*> Q; 5 Q.push(p); //根节点进队 6 BinTreeNode<T>* t; 7 while (!Q.empty()) 8 { 9 t = Q.front(); //t先记住队头,再将队头出队 10 Q.pop(); 11 cout << t->data << " "; //访问队头元素的数据 12 13 if (t->leftChild != NULL) 14 { 15 Q.push(t->leftChild); 16 } 17 18 if (t->rightChild != NULL) 19 { 20 Q.push(t->rightChild); 21 } 22 } 23 }
二叉树的结点个数
1 //计算二叉树以subTree为根的结点的个数 2 int Size(BinTreeNode<T> *subTree) const 3 { 4 if (subTree == NULL) //递归结束,空树结点个数为0 5 { 6 return 0; 7 } 8 return 1 + Size(subTree->leftChild) + Size(subTree->rightChild); 9 }
二叉树的高度
1 //计算二叉数以subTree为根的高度 2 int Height(BinTreeNode<T> *subTree) 3 { 4 if (subTree == NULL) //递归结束,空树高度为0 5 { 6 return 0; 7 } 8 int i = Height(subTree->leftChild); 9 int j = Height(subTree->rightChild); 10 return i < j ? j + 1 : i + 1; 11 }
以广义表的形式输出二叉树
1 void PrintBinTree(BinTreeNode<T> *BT) 2 { 3 if (BT != NULL) //树为空时结束递归 4 { 5 cout << BT->data; 6 if (BT->leftChild != NULL || BT->rightChild != NULL) 7 { 8 cout << ‘(‘; 9 if (BT->leftChild!=NULL) 10 { 11 PrintBinTree(BT->leftChild); 12 } 13 cout << ‘,‘; 14 if (BT->rightChild != NULL) 15 { 16 PrintBinTree(BT->rightChild); 17 } 18 cout << ‘)‘; 19 } 20 } 21 }
求二叉树某结点的父节点
1 //从结点subTree开始,搜索结点current的父节点,找到返回父节点的地址,找不到返回NULL 2 BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current) 3 { 4 if (subTree == NULL) 5 { 6 return NULL; 7 } 8 if (subTree->leftChild == current || subTree->rightChild == current) //如果找到,返回父节点subTree 9 { 10 return subTree; 11 } 12 BinTreeNode<T>* p; 13 if (p = Parent(subTree->leftChild, current) != NULL) //递归在左子树中搜索 14 { 15 return p; 16 } 17 else 18 { 19 return Parent(subTree->rightChild, current); //递归右子树中搜索 20 } 21 }
二叉树的销毁
1 //二叉树的销毁函数 2 void Destroy(BinTreeNode<T> *&subTree) 3 { 4 if (subTree != NULL) 5 { 6 Destroy(subTree->leftChild); 7 Destroy(subTree->rightChild); 8 delete subTree; 9 subTree = NULL; 10 } 11 }
判断两颗二叉树是否相等
1 //判断两颗二叉树是否相等 2 bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b) 3 { 4 if (a == NULL&&b == NULL) //两者都为空 5 { 6 return true; 7 } 8 if (a != NULL&&b != NULL&&a->data == b->data&&equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild)) //两者都不为空,且两者的结点数据相等,且两者的左右子树的结点都相等 9 { 10 return true; 11 } 12 return false; 13 }
完整代码:
二叉树
1 //结点类型 2 template<typename T> 3 struct BinTreeNode 4 { 5 T data; //结点中存储的数据 6 BinTreeNode<T> *leftChild, *rightChild; //左子树和右子树 7 BinTreeNode() :leftChild(NULL), rightChild(NULL) {} //无参构造函数 8 BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) :data(x), leftChild(l), rightChild(r) {} //带默认值的有参构造参数 9 }; 10 11 //后续遍历(非递归)所用的注明左右的结点的类型 12 template<typename T> 13 struct stkNode 14 { 15 BinTreeNode<T> *ptr; //指向树结点的指针 16 enum tag { L, R }; //该结点退栈的标记 17 stkNode(BinTreeNode<T> *N = NULL) :ptr(N), tag(L) {} //带默认值的有参构造函数 18 }; 19 20 //二叉树类 21 template<typename T> 22 class BinaryTree 23 { 24 public: 25 //构造函数 26 BinaryTree() :root(NULL) {} 27 //指定结束标志的构造函数 28 BinaryTree(T value) :RefValue(value), root(NULL) {} 29 //复制构造函数(前序遍历的应用) 30 BinaryTree(BinaryTree<T>& s) 31 { 32 root = Copy(s.getRoot()); 33 } 34 //判断两颗二叉树是否相等(前序遍历的应用) 35 bool operator==(BinaryTree<T>& s) 36 { 37 return (equal(this->getRoot(), s.getRoot())); 38 } 39 //析构函数 40 ~BinaryTree() { Destroy(root); } 41 //创建二叉树(使用广义表创建) 42 void CreateBinTree() { CreateBinTree(root); } 43 //创建二叉树(利用二叉树的前序遍历创建)(前序遍历的应用) 44 void CreateBinTree_PreOrder() { CreateBinTree_PreOrder(root); } 45 //二叉树中序遍历(递归) 46 void InOrder() { InOrder(root); } 47 48 //二叉树先序遍历(递归) 49 void PreOrder() { PreOrder(root); } 50 //二叉树先序遍历(非递归1) 51 void PreOrder_NoRecurve1() { PreOrder_NoRecurve1(root); } 52 //二叉树先序遍历(非递归2) 53 void PreOrder_NoRecurve2() { PreOrder_NoRecurve2(root); } 54 55 //二叉树后序遍历(递归) 56 void PostOrder() { PostOrder(root); } 57 58 //二叉树的层次遍历(非递归遍历) 59 void LevelOrder() { LevelOrder(root); } 60 61 62 //二叉树的中序遍历(非递归) 63 void InOrder_NoRecurve() { InOrder_NoRecurve(root); } 64 65 //计算二叉树的结点的个数(后序遍历的应用) 66 int Size() { return Size(root); } 67 //计算二叉树的高度(后序遍历的应用) 68 int Height() { return Height(root); } 69 70 //销毁函数 71 void Destroy() { Destroy(root); } 72 //返回current结点的父节点 73 BinTreeNode<T>* Parent(BinTreeNode<T>* current) 74 { 75 return (root == NULL || root == current) ? NULL : Parent(root, current); //如果没有根节点或current结点就是root结点,就没有父节点 76 } 77 //判断二叉树是否为空 78 bool Empty() { return (root == NULL) ? true : false; } 79 //返回current结点的左结点 80 BinTreeNode<T>* LeftChild(BinTreeNode<T>* current) 81 { 82 return (current != NULL) ? current->leftChild : NULL; 83 } 84 //返回current结点的右结点 85 BinTreeNode<T>* RightChild(BinTreeNode<T>* current) 86 { 87 return (current != NULL) ? current->rightChild : NULL; 88 } 89 //获取二叉树的根节点 90 BinTreeNode<T>* getRoot() const 91 { 92 return root; 93 } 94 //以广义表的形式输出二叉树(前序遍历的应用) 95 void PrintBinTree() { PrintBinTree(root); } 96 //二叉树的后序遍历(非递归) 97 void PostOrder_NoRecurve() { PostOrder_NoRecurve(root); } 98 99 100 protected: 101 //使用广义表创建二叉树函数,这里以“字符”创建二叉树,以‘#‘字符代表结束 102 void CreateBinTree(BinTreeNode<T>* &BT) 103 { 104 stack< BinTreeNode<T>* > s; 105 BT = NULL; 106 BinTreeNode<T> *p, *t; //p用来记住当前创建的节点,t用来记住栈顶的元素 107 int k; //k是处理左、右子树的标记 108 T ch; 109 cin >> ch; 110 111 while (ch != RefValue) 112 { 113 switch (ch) 114 { 115 case ‘(‘: //对(做处理 116 s.push(p); 117 k = 1; 118 break; 119 120 case ‘)‘: //对)做处理 121 s.pop(); 122 break; 123 124 case ‘,‘: //对,做处理 125 k = 2; 126 break; 127 128 default: 129 p = new BinTreeNode<T>(ch); //构造一个结点 130 if (BT == NULL) //如果头节点是空 131 { 132 BT = p; 133 } 134 else if (k == 1) //链入*t的左孩子 135 { 136 t = s.top(); 137 t->leftChild = p; 138 } 139 else //链入*t的右孩子 140 { 141 t = s.top(); 142 t->rightChild = p; 143 } 144 } 145 cin >> ch; 146 } 147 } 148 149 //二叉树的中序遍历 150 void InOrder(BinTreeNode<T> *&subTree) 151 { 152 if (subTree != NULL) 153 { 154 InOrder(subTree->leftChild); 155 cout << subTree->data << " "; 156 InOrder(subTree->rightChild); 157 } 158 } 159 160 //二叉树的先序遍历 161 void PreOrder(BinTreeNode<T> *&subTree) 162 { 163 if (subTree != NULL) 164 { 165 cout << subTree->data << " "; 166 PreOrder(subTree->leftChild); 167 PreOrder(subTree->rightChild); 168 } 169 } 170 171 //二叉树的后序遍历 172 void PostOrder(BinTreeNode<T> *&subTree) 173 { 174 if (subTree != NULL) 175 { 176 PostOrder(subTree->leftChild); 177 PostOrder(subTree->rightChild); 178 cout << subTree->data << " "; 179 } 180 } 181 182 //计算二叉树以subTree为根的结点的个数 183 int Size(BinTreeNode<T> *subTree) const 184 { 185 if (subTree == NULL) //递归结束,空树结点个数为0 186 { 187 return 0; 188 } 189 return 1 + Size(subTree->leftChild) + Size(subTree->rightChild); 190 } 191 192 //计算二叉数以subTree为根的高度 193 int Height(BinTreeNode<T> *subTree) 194 { 195 if (subTree == NULL) //递归结束,空树高度为0 196 { 197 return 0; 198 } 199 int i = Height(subTree->leftChild); 200 int j = Height(subTree->rightChild); 201 return i < j ? j + 1 : i + 1; 202 } 203 204 //二叉树的销毁函数 205 void Destroy(BinTreeNode<T> *&subTree) 206 { 207 if (subTree != NULL) 208 { 209 Destroy(subTree->leftChild); 210 Destroy(subTree->rightChild); 211 delete subTree; 212 subTree = NULL; 213 } 214 } 215 216 //从结点subTree开始,搜索结点current的父节点,找到返回父节点的地址,找不到返回NULL 217 BinTreeNode<T>* Parent(BinTreeNode<T>* subTree, BinTreeNode<T>* current) 218 { 219 if (subTree == NULL) 220 { 221 return NULL; 222 } 223 if (subTree->leftChild == current || subTree->rightChild == current) //如果找到,返回父节点subTree 224 { 225 return subTree; 226 } 227 BinTreeNode<T>* p; 228 if (p = Parent(subTree->leftChild, current) != NULL) //递归在左子树中搜索 229 { 230 return p; 231 } 232 else 233 { 234 return Parent(subTree->rightChild, current); //递归右子树中搜索 235 } 236 } 237 238 //复制构造函数调用的Copy函数,返回一个指针,给出一个以originNode为根的二叉树的副本 239 BinTreeNode<T>* Copy(BinTreeNode<T>* originNode) 240 { 241 if (originNode == NULL) 242 { 243 return NULL; 244 } 245 BinTreeNode<T>* temp = new BinTreeNode<T>; //创建根结点 246 temp->data = originNode->data; 247 temp->leftChild = Copy(originNode->leftChild); 248 temp->rightChild = Copy(originNode->rightChild); 249 return temp; 250 251 } 252 //判断两颗二叉树是否相等 253 bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b) 254 { 255 if (a == NULL&&b == NULL) //两者都为空 256 { 257 return true; 258 } 259 if (a != NULL&&b != NULL&&a->data == b->data&&equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild)) //两者都不为空,且两者的结点数据相等,且两者的左右子树的结点都相等 260 { 261 return true; 262 } 263 return false; 264 } 265 //创建二叉树(利用已知的二叉树的前序遍历创建)用#表示空结点 266 void CreateBinTree_PreOrder(BinTreeNode<T>* &subTree) 267 { 268 T item; 269 if (cin >> item) 270 { 271 if (item != RefValue) 272 { 273 subTree = new BinTreeNode<T>(item); //构造结点 274 if (subTree == NULL) 275 { 276 cout << "空间分配错误!" << endl; 277 exit(1); 278 } 279 CreateBinTree_PreOrder(subTree->leftChild); //递归创建左子树 280 CreateBinTree_PreOrder(subTree->rightChild); //递归创建右子树 281 } 282 else 283 { 284 subTree == NULL; 285 } 286 } 287 } 288 //以广义表的形式输出二叉树 289 void PrintBinTree(BinTreeNode<T> *BT) 290 { 291 if (BT != NULL) //树为空时结束递归 292 { 293 cout << BT->data; 294 if (BT->leftChild != NULL || BT->rightChild != NULL) 295 { 296 cout << ‘(‘; 297 if (BT->leftChild!=NULL) 298 { 299 PrintBinTree(BT->leftChild); 300 } 301 cout << ‘,‘; 302 if (BT->rightChild != NULL) 303 { 304 PrintBinTree(BT->rightChild); 305 } 306 cout << ‘)‘; 307 } 308 } 309 } 310 //二叉树先序遍历(非递归1) 311 void PreOrder_NoRecurve1(BinTreeNode<T> *p) 312 { 313 stack<BinTreeNode<T>*> S; 314 S.push(NULL); //最先push一个NULL,到最后一个结点没有左右子树时,栈里只有一个NULL了,令指针p指向这个NULL,再判断就会结束循环 315 while (p!=NULL) 316 { 317 cout << p->data << " "; 318 if(p->rightChild!=NULL) //预留右子树指针在栈中 319 { 320 S.push(p->rightChild); 321 } 322 323 if (p->leftChild!=NULL) //进左子树 324 { 325 p = p->leftChild; 326 } 327 else //左子树为空 328 { 329 p = S.top(); 330 S.pop(); 331 } 332 } 333 } 334 //二叉树先序遍历(非递归2) 335 void PreOrder_NoRecurve2(BinTreeNode<T> *p) 336 { 337 stack<BinTreeNode<T>*> S; 338 BinTreeNode<T>* t; 339 S.push(p); //根节点进栈 340 while (!S.empty()) //当栈不为空 341 { 342 t = S.top(); //p先记住栈顶元素,然后栈顶出栈 343 S.pop(); 344 cout << t->data << " "; //访问元素 345 if (t->rightChild != NULL) //右孩子不为空,右孩子近栈 346 { 347 S.push(t->rightChild); 348 } 349 if (t->leftChild != NULL) //左孩子不为空,左孩子进栈 350 { 351 S.push(t->leftChild); 352 } 353 } 354 } 355 356 //二叉树的层次遍历(非递归遍历) 357 void LevelOrder(BinTreeNode<T> *p) 358 { 359 queue<BinTreeNode<T>*> Q; 360 Q.push(p); //根节点进队 361 BinTreeNode<T>* t; 362 while (!Q.empty()) 363 { 364 t = Q.front(); //t先记住队头,再将队头出队 365 Q.pop(); 366 cout << t->data << " "; //访问队头元素的数据 367 368 if (t->leftChild != NULL) 369 { 370 Q.push(t->leftChild); 371 } 372 373 if (t->rightChild != NULL) 374 { 375 Q.push(t->rightChild); 376 } 377 } 378 } 379 380 //二叉树的中序遍历(非递归) 381 void InOrder_NoRecurve(BinTreeNode<T>* p) 382 { 383 stack<BinTreeNode<T>*> S; 384 do 385 { 386 while (p!=NULL) 387 { 388 S.push(p); 389 p = p->leftChild; 390 } 391 if (!S.empty()) 392 { 393 p = S.top(); 394 S.pop(); 395 cout << p->data << " "; 396 p = p->rightChild; 397 } 398 } 399 while (p!=NULL||!S.empty()); 400 } 401 402 //二叉树的后序遍历(非递归) 403 void PostOrder(BinTreeNode<T>* p) 404 { 405 stack<stkNode<T>> S; //创建一个栈 406 stkNode<T> w; //创建一个注明左右类型的结点 407 do 408 { 409 while (p != NULL) //循环将左结点压栈 410 { 411 w.ptr = p; 412 w.tag = L; 413 S.push(w); 414 p = p->leftChild; 415 } 416 int flag = 1; //默认flag为1 417 while (flag&&S.empty()) 418 { 419 w = S.top(); //记住栈顶元素并出栈 420 S.pop(); 421 p = w.ptr; //并使p指向记住的栈顶元素中存储的结点 422 switch (w.tag) 423 { 424 case L: //若标记为左,就将标志改为右,再进栈 425 w.tag = R; 426 S.push(w); 427 flag = 0; //flag置为0 428 p = p->rightChild; 429 break; 430 case R: //若标记为右孩子 431 cout << p->data << " "; 432 break; 433 } 434 } 435 } 436 while (!S.empty()); 437 cout << endl; 438 } 439 private: 440 BinTreeNode<T>* root; //根节点 441 T RefValue; //数据输入停止的标志,需要一个构造函数 442 };
测试函数:
主函数测试
1 int main(int argc, char* argv[]) 2 { 3 //A(B(D,E(G,)),C(,F))# 4 //abc##de#g##f### 5 BinaryTree<char> tree(‘#‘); //调用以#号结束的构造函数 6 tree.CreateBinTree(); 7 8 cout << "中序遍历:"; 9 tree.InOrder(); 10 cout << endl; 11 12 cout << "先序遍历:"; 13 tree.PreOrder(); 14 cout << endl; 15 16 cout << "后序遍历:"; 17 tree.PostOrder(); 18 cout << endl; 19 20 cout << "二叉树的结点的个数是:" << tree.Size() << endl; 21 cout << "二叉树的高度是:" << tree.Height() << endl; 22 23 BinaryTree<char> tree1(tree); 24 cout << "tree和tree1是否相等:"; 25 cout << (tree==tree1)<<endl; 26 27 //使用前序遍历创建二叉树 28 BinaryTree<char> tree2(‘#‘); 29 tree2.CreateBinTree_PreOrder(); 30 31 cout << "先序遍历:"; 32 tree2.PreOrder(); 33 34 cout << "先序遍历非递归1:"; 35 tree2.PreOrder_NoRecurve1(); 36 37 cout << "先序遍历非递归2:"; 38 tree2.PreOrder_NoRecurve2(); 39 40 cout << "层次遍历:"; 41 tree2.LevelOrder(); 42 43 cout << "中序遍历非递归:"; 44 tree2.InOrder_NoRecurve(); 45 46 cout << "\\n广义表输出二叉树:"; 47 tree2.PrintBinTree(); 48 return 0; 49 }
以上是关于二叉树的详细实现 (C++)的主要内容,如果未能解决你的问题,请参考以下文章
精选力扣500题 第35题 LeetCode 94. 二叉树的中序遍历c++ / java 详细题解
精选力扣500题 第13题 LeetCode 102. 二叉树的层序遍历c++详细题解
精选力扣500题 第19题 LeetCode 199. 二叉树的右视图c++详细题解