赞
踩
关于二叉树的概念,已经在树的基本概念中详细描述,这里不做过多赘述。本文将对二叉树进行详细实现,采用 C++ 语言。
template <typename T>
struct BinTreeNode
{
T data; //结点中存储的数据
BinTreeNode<T> *leftChild, *rightChild; //左子树和右子树
BinTreeNode() : leftChild(NULL), rightChild(NULL) {} //无参构造函数
BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) : data(x), leftChild(l), rightChild(r) {} //带默认值的有参构造参数
};
下面是二叉树的一些常用的方法,各个方法具体实现在后面将会给出。
//二叉树的类声明 template <typename T> class BinaryTree { public: //构造函数 BinaryTree() : root(NULL) {} //指定结束标志的构造函数 BinaryTree(T value) : root(NULL), RefValue(value) {} //析构函数 ~BinaryTree(); //拷贝构造函数,拷贝二叉树(前序遍历的应用) BinaryTree(BinaryTree<T> &s); //使用广义表创建二叉树,以'#'字符代表结束 void CreateBinTree(); //前序遍历创建二叉树(前序遍历的应用),用#表示空结点 void CreateBinTree_PreOrder(); //使用先序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Pre_In(const char *pre, const char *in); //使用后序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Post_In(const char *post, const char *in); //先序遍历(递归) void PreOrder(); //中序遍历(递归) void InOrder(); //后序遍历(递归) void PostOrder(); //先序遍历(非递归1) void PreOrder_NoRecurve1(); //先序遍历(非递归2) void PreOrder_NoRecurve2(); //中序遍历(非递归) void InOrder_NoRecurve(); //后序遍历(非递归) void PostOrder_NoRecurve(); //层次遍历(非递归) void LevelOrder(); //获取二叉树的根节点 BinTreeNode<T> *getRoot(); //获取current结点的父节点 BinTreeNode<T> *Parent(BinTreeNode<T> *current); //获取current结点的左结点 BinTreeNode<T> *LeftChild(BinTreeNode<T> *current); //获取current结点的右结点 BinTreeNode<T> *RightChild(BinTreeNode<T> *current); //销毁函数 void Destroy(); //判断两颗二叉树是否相等(前序遍历的应用) bool operator==(BinaryTree<T> &s); //计算二叉树的结点的个数(后序遍历的应用) int Size(); //计算二叉树的高度(后序遍历的应用) int Height(); //判断二叉树是否为空 bool Empty(); //以广义表的形式输出二叉树(前序遍历的应用) void PrintBinTree(); //翻转二叉树 void InvertTree(); private: BinTreeNode<T> *root; //根节点 T RefValue; //数据输入停止的标志,需要一个构造函数 };
比如从广义表: A(B(D,E(G,)),C(,F))# 建立起来的二叉树如下:
该算法的基本思路:
若是字母(假定以字母作为结点的值),则表示是结点的值,为它建立一个新的结点,并把该结点作为左子女(当 k=1)或右子女(当 k=2)链接到其父结点上。
若是左括号 (
,则表明子表的开始,将 k 置为 1;若遇到的是右括号 )
,则表明子表结束。
遇到的是逗号 ,
,则表示以左子女为根的子树处理完毕,应接着处理以右子女为根的子树,将 k 置为 2。如此处理每一个字符,直到读入结束符 #
为止。
在算法中使用了一个栈 s
,在进入子表之前将根结点指针进栈,以便括号内的子女链接之用。在子表处理结束时退栈。
//使用广义表创建二叉树函数,这里以"字符"创建二叉树,以'#'字符代表结束 void CreateBinTree(BinTreeNode<T> *&BT) { stack<BinTreeNode<T> *> s; BT = NULL; BinTreeNode<T> *p = NULL; //p用来记住当前创建的节点, BinTreeNode<T> *t = NULL; //t用来记住栈顶的元素 int k = 0; //k是处理左、右子树的标记 T ch; cin >> ch; while (ch != RefValue) { switch (ch) { case '(': //对(做处理 s.push(p); k = 1; break; case ')': //对)做处理 s.pop(); break; case ',': //对,做处理 k = 2; break; default: p = new BinTreeNode<T>(ch); //构造一个结点 if (BT == NULL) //如果头节点是空 { BT = p; } else if (k == 1) //链入*t的左孩子 { t = s.top(); t->leftChild = p; } else if(k == 2) //链入*t的右孩子 { t = s.top(); t->rightChild = p; } } cin >> ch; } } /*算法过程逐步分解,第一列是每次输入的字符,第二列是当前步骤p或k的值,第三列S表示栈中的元素,左边是栈顶: A p = A S: ( k=1 S: A B p = B A->left = B ( k=1 S: B A D p = D B->left = D , k=2 E p = E B->right = E ( k=1 S: E B A G p = G E->left = G , k=2 ) S: B A ) S: A , k=2 C p = C A->right = C ( k=1 S: C A , k=2 F p = F C->right = F ) S: A ) S: # end */
必须对应二又树结点前序遍历的顺序,并约定以输入序列中不可能出现的值作为空结点的值以结束递归,此值通过构造函数存放在 RefValue 中。例如用 #
表示正整数序列空结点。
该二叉树前序遍历所得到的前序序列为:ABC##DE#G##F###
。
构建该二叉树的算法基本思想是:
每读入一个值,就为它建立结点。该结点作为根结点,其地址通过函数的引用型参数 subTree 直接链接到作为实际参数的指针中。然后,分别对根的左、右子树递归地建立子树,直到读入#
建立空子树递归结束。
创建二叉树(利用已知的二叉树的前序遍历创建)用'#'表示空结点 void CreateBinTree_PreOrder(BinTreeNode<T> *&subTree) { T item; if (cin >> item) { if (item != RefValue) { subTree = new BinTreeNode<T>(item); //构造结点 if (subTree == NULL) { cout << "空间分配错误!" << endl; exit(1); } CreateBinTree_PreOrder(subTree->leftChild); //递归创建左子树 CreateBinTree_PreOrder(subTree->rightChild); //递归创建右子树 } else { subTree = NULL; } } }
根据前序遍历,先找到这棵树的根节点,也就是数组中第一个结点的位置,创建根节点。
然后在中序遍历中找到根的值所在的下标,切出左右子树的前序和中序。
注意:如果前序遍历的数组长度为 0,说明是一棵空树。
举例:
如果最终的二叉树如下:
给出的前序遍历和中序遍历如下:
前序遍历:A B C D E
中序遍历:C D B A E
首先可以确定 A 是这棵树的根节点,然后根据中序遍历切出 A 的左右子树,得到 BCD 属于 A 的左子树,E 属于 A 的右子树,如下图:
接着以 B 为根节点,在中序遍历中再次切出 B 的左右子树,得到 CD 为 B 的左子树,右子树为空。
再以 C 为根节点,结合中序遍历,得到 D 为 C 的右子树,左子树为空。
其代码实现如下:
//使用先序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Pre_In(BinTreeNode<T> *&cur, const char *pre, const char *in, int n) { if (n <= 0) { cur = NULL; return; } int k = 0; while (pre[0] != in[k]) //再中序中找到pre[0]的值 { k++; } cur = new BinTreeNode<T>(in[k]); //创建结点 CreateBinTreeBy_Pre_In(cur->leftChild, pre + 1, in, k); CreateBinTreeBy_Pre_In(cur->rightChild, pre + k + 1, in + k + 1, n - k - 1); }
根据后序遍历,先找到这棵树的根节点的值,也就是数组中最后一个节点(数组长度 -1)的位置,由此创建根节点。
然后在中序遍历中找到根的值所在的下标,切出左右子树的后续和中序。
注意:如果后序遍历的数组长度为 0,说明是一棵空树。
举例:
还是给出上面例子的二叉树的后序遍历和中序遍历:
中序遍历:C D B A E
后续遍历:D C B E A
由后序遍历可以确定 A 是这棵树的根节点,然后根据中序遍历切出 A 的左右子树,得到 CDB 属于 A 的左子树,E 属于 A 的右子树,如下图:
接着以 B 为根节点,在中序遍历中再次切出 B 的左右子树,得到 CD 为 B 的左子树,右子树为空。
再以 C 为根节点,结合中序遍历,得到 D 为 C 的右子树,左子树为空。
其代码实现如下:
//使用后序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Post_In(BinTreeNode<T> *&cur, const char *post, const char *in, int n) { if (n == 0) { cur = NULL; return; } char r = *(post + n - 1); //根结点值 cur = new BinTreeNode<T>(r); //构造当前结点 int k = 0; const char *p = in; while (*p != r) { k++; p++; } CreateBinTreeBy_Post_In(cur->leftChild, post, in, k); CreateBinTreeBy_Post_In(cur->rightChild, post + k, p + 1, n - k - 1); }
二叉树的先序遍历顺序为:根结点 -> 左孩子结点 -> 右孩子结点
//二叉树的先序遍历
void PreOrder(BinTreeNode<T> *&subTree)
{
if (subTree != NULL)
{
cout << subTree->data << " ";
PreOrder(subTree->leftChild);
PreOrder(subTree->rightChild);
}
}
二叉树的中序遍历顺序为:左孩子结点 -> 根结点 -> 右孩子结点
//二叉树的中序遍历
void InOrder(BinTreeNode<T> *&subTree)
{
if (subTree != NULL)
{
InOrder(subTree->leftChild);
cout << subTree->data << " ";
InOrder(subTree->rightChild);
}
}
二叉树的后序遍历顺序为:左孩子结点 -> 右孩子结点 -> 根节点
//二叉树的后序遍历
void PostOrder(BinTreeNode<T> *&subTree)
{
if (subTree != NULL)
{
PostOrder(subTree->leftChild);
PostOrder(subTree->rightChild);
cout << subTree->data << " ";
}
}
为了把一个递归过程改为非递归过程,一般需要利用一个工作栈,记录遍历时的回退路径。
利用栈实现前序遍历的过程。每次访问一个结点后,在向左子树遍历下去之前,利用这个栈记录该结点的右子女(如果有的话)结点的地址,以便在左子树退回时可以直接从栈顶取得右子树的根结点,继续其右子树的前序遍历。
//二叉树的先序遍历(非递归1) void PreOrder_NoRecurve1(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; S.push(NULL); //最先push一个NULL,到最后一个结点没有左右子树时,栈里只有一个NULL了,令指针p指向这个NULL,再判断就会结束循环 while (p != NULL) { cout << p->data << " "; if (p->rightChild != NULL) //预留右子树指针在栈中 { S.push(p->rightChild); } if (p->leftChild != NULL) //进左子树 { p = p->leftChild; } else //左子树为空 { p = S.top(); S.pop(); } } }
另一种前序遍历的方法。为了保证先左子树后右子树的顺序,在进栈时是先进右子女结点地址,后进左子女结点地址,出栈时正好相反。
//二叉树的先序遍历(非递归2) void PreOrder_NoRecurve2(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; BinTreeNode<T> *t; S.push(p); //根节点进栈 while (!S.empty()) //当栈不为空 { t = S.top(); //p先记住栈顶元素,然后栈顶出栈 S.pop(); cout << t->data << " "; //访问元素 if (t->rightChild != NULL) //右孩子不为空,右孩子近栈 { S.push(t->rightChild); } if (t->leftChild != NULL) //左孩子不为空,左孩子进栈 { S.push(t->leftChild); } } }
需要使用一个栈,以记录遍历过程中回退的路径。在一棵子树中首先访问的是中序下的第一个结点,它位于从根开始沿leftChild链走到最左下角的结点,该结点的leftChild指针为NULL。访问它的数据之后,再遍历该结点的右子树。此右子树又是二叉树,重复执行上面的过程,直到该子树遍历完。如下图:
如果某结点的右子树遍历完或右子树为空,说明以这个结点为根的二叉树遍历完,此时从栈中退出更上层的结点并访问它,再向它的右子树遍历下去。
//二叉树的中序遍历(非递归) void InOrder_NoRecurve(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; do { while (p != NULL) { S.push(p); p = p->leftChild; } if (!S.empty()) { p = S.top(); S.pop(); cout << p->data << " "; p = p->rightChild; } } while (p != NULL || !S.empty()); }
该思想是:
第 1 步:如果栈顶元素非空且左节点存在,将其压入栈中,如果栈顶元素存在左节点,将其左节点压栈,重复该过程。直到左结点不存在则进入第 2 步。
第 2 步:判断上一次出栈节点是否是当前栈顶结点的右节点(就是右叶子结点,如:G、F结点),或者当前栈顶结点不存在右结点(如:G,F,A结点),将当前节点输出,并出栈。否则将当前栈顶结点右孩子节点压栈,再进入第 1 步。
//二叉树的后序遍历(非递归) void PostOrder_NoRecurve(BinTreeNode<T> *p) { if (root == NULL) return; stack<BinTreeNode<T> *> s; s.push(p); BinTreeNode<T> *lastPop = NULL; while (!s.empty()) { while (s.top()->leftChild != NULL) s.push(s.top()->leftChild); while (!s.empty()) { //右叶子结点 || 没有右结点 if (lastPop == s.top()->rightChild || s.top()->rightChild == NULL) { cout << s.top()->data << " "; lastPop = s.top(); s.pop(); } else if (s.top()->rightChild != NULL) { s.push(s.top()->rightChild); break; } } } }
按层次顺序访问二叉树的处理需要利用一个队列。在访问二又树的某一层结点时,把下一层结点指针预先记忆在队列中,利用队列安排逐层访问的次序。因此,每当访问一个结点时,将它的子女依次加到队列的队尾,然后再访问已在队列队头的结点。这样可以实现二又树结点的按层访问。
//二叉树的层次遍历(非递归遍历) void LevelOrder(BinTreeNode<T> *p) { queue<BinTreeNode<T> *> Q; Q.push(p); //根节点进队 BinTreeNode<T> *t; while (!Q.empty()) { t = Q.front(); //t先记住队头,再将队头出队 Q.pop(); cout << t->data << " "; //访问队头元素的数据 if (t->leftChild != NULL) { Q.push(t->leftChild); } if (t->rightChild != NULL) { Q.push(t->rightChild); } } }
//计算二叉树以subTree为根的结点的个数
int Size(BinTreeNode<T> *subTree) const
{
if (subTree == NULL) //递归结束,空树结点个数为0
{
return 0;
}
return 1 + Size(subTree->leftChild) + Size(subTree->rightChild);
}
//计算二叉数以subTree为根的高度
int Height(BinTreeNode<T> *subTree)
{
if (subTree == NULL) //递归结束,空树高度为0
{
return 0;
}
int i = Height(subTree->leftChild);
int j = Height(subTree->rightChild);
return i < j ? j + 1 : i + 1;
}
//以广义表的形式输出二叉树 void PrintBinTree(BinTreeNode<T> *BT) { if (BT != NULL) //树为空时结束递归 { cout << BT->data; if (BT->leftChild != NULL || BT->rightChild != NULL) { cout << '('; if (BT->leftChild != NULL) { PrintBinTree(BT->leftChild); } cout << ','; if (BT->rightChild != NULL) { PrintBinTree(BT->rightChild); } cout << ')'; } } }
//从结点subTree开始,搜索结点current的父节点,找到返回父节点的地址,找不到返回NULL BinTreeNode<T> *Parent(BinTreeNode<T> *subTree, BinTreeNode<T> *current) { if (subTree == NULL) { return NULL; } if (subTree->leftChild == current || subTree->rightChild == current) //如果找到,返回父节点subTree { return subTree; } BinTreeNode<T> *p; if (p = Parent(subTree->leftChild, current) != NULL) //递归在左子树中搜索 { return p; } else { return Parent(subTree->rightChild, current); //递归右子树中搜索 } }
//二叉树的销毁
void Destroy(BinTreeNode<T> *&subTree)
{
if (subTree != NULL)
{
Destroy(subTree->leftChild);
Destroy(subTree->rightChild);
delete subTree;
subTree = NULL;
}
}
//判断两颗二叉树是否相等
bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b)
{
if (a == NULL && b == NULL) //两者都为空
{
return true;
}
if (a != NULL && b != NULL && a->data == b->data && equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild)) //两者都不为空,且两者的结点数据相等,且两者的左右子树的结点都相等
{
return true;
}
return false;
}
//复制二叉树,返回一个指针,给出一个以originNode为根复制的二叉树的副本
BinTreeNode<T> *Copy(BinTreeNode<T> *originNode)
{
if (originNode == NULL)
{
return NULL;
}
BinTreeNode<T> *temp = new BinTreeNode<T>; //创建根结点
temp->data = originNode->data;
temp->leftChild = Copy(originNode->leftChild);
temp->rightChild = Copy(originNode->rightChild);
return temp;
}
/*二叉树的翻转 给定一颗二叉树 4 / \ 2 7 / \ / \ 1 3 6 9 将二叉树翻转后: 4 / \ 7 2 / \ / \ 9 6 3 1 */ void InvertTree(BinTreeNode<T> *originNode) { if (originNode == null) return null; BinTreeNode<T> * tempNode = originNode->leftChild; originNode.leftChild = originNode->rightChild; originNode.rightChild = tempNode; InvertTree(originNode->leftChild); InvertTree(originNode->rightChild); }
#include <iostream> #include <stack> #include <queue> #include <string.h> using namespace std; //二叉树结点类型定义 template <typename T> struct BinTreeNode { T data; //结点中存储的数据 BinTreeNode<T> *leftChild, *rightChild; //左子树和右子树 BinTreeNode() : leftChild(NULL), rightChild(NULL) {} //无参构造函数 BinTreeNode(T x, BinTreeNode<T> *l = NULL, BinTreeNode<T> *r = NULL) : data(x), leftChild(l), rightChild(r) {} //带默认值的有参构造参数 }; //二叉树的详细实现 template <typename T> class BinaryTree { public: //构造函数 BinaryTree() : root(NULL) {} //指定结束标志的构造函数 BinaryTree(T value) : root(NULL), RefValue(value) {} //析构函数 ~BinaryTree() { Destroy(root); } //拷贝构造函数,拷贝二叉树(前序遍历的应用) BinaryTree(BinaryTree<T> &s) { root = Copy(s.getRoot()); } //使用广义表创建二叉树,以'#'字符代表结束 void CreateBinTree() { CreateBinTree(root); } //前序遍历创建二叉树(前序遍历的应用),用#表示空结点 void CreateBinTree_PreOrder() { CreateBinTree_PreOrder(root); } //使用先序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Pre_In(const char *pre, const char *in) { CreateBinTreeBy_Pre_In(root, pre, in, strlen(pre)); }; //使用后序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Post_In(const char *post, const char *in) { CreateBinTreeBy_Post_In(root, post, in, strlen(post)); }; //先序遍历(递归) void PreOrder() { PreOrder(root); } //中序遍历(递归) void InOrder() { InOrder(root); } //后序遍历(递归) void PostOrder() { PostOrder(root); } //先序遍历(非递归1) void PreOrder_NoRecurve1() { PreOrder_NoRecurve1(root); } //先序遍历(非递归2) void PreOrder_NoRecurve2() { PreOrder_NoRecurve2(root); } //中序遍历(非递归) void InOrder_NoRecurve() { InOrder_NoRecurve(root); } //后序遍历(非递归) void PostOrder_NoRecurve() { PostOrder_NoRecurve(root); } //层次遍历(非递归) void LevelOrder() { LevelOrder(root); } //获取二叉树的根节点 BinTreeNode<T> *getRoot() const { return root; } //获取current结点的父节点 BinTreeNode<T> *Parent(BinTreeNode<T> *current) { return (root == NULL || root == current) ? NULL : Parent(root, current); } //如果没有根节点或current结点就是root结点,就没有父节点 //获取current结点的左结点 BinTreeNode<T> *LeftChild(BinTreeNode<T> *current) { return (current != NULL) ? current->leftChild : NULL; } //获取current结点的右结点 BinTreeNode<T> *RightChild(BinTreeNode<T> *current) { return (current != NULL) ? current->rightChild : NULL; } //销毁函数 void Destroy() { Destroy(root); }; //判断两颗二叉树是否相等(前序遍历的应用) bool operator==(BinaryTree<T> &s) { return (equal(this->getRoot(), s.getRoot())); } //计算二叉树的结点的个数(后序遍历的应用) int Size() { return Size(root); } //计算二叉树的高度(后序遍历的应用) int Height() { return Height(root); } //判断二叉树是否为空 bool Empty() { return (root == NULL) ? true : false; } //以广义表的形式输出二叉树(前序遍历的应用) void PrintBinTree() { PrintBinTree(root); } //翻转二叉树 void InvertTree() { InvertTree(root); } protected: //使用广义表创建二叉树函数,这里以'字符'创建二叉树,以'#'字符代表结束 void CreateBinTree(BinTreeNode<T> *&BT) { stack<BinTreeNode<T> *> s; BT = NULL; BinTreeNode<T> *p, *t; //p用来记住当前创建的节点,t用来记住栈顶的元素 int k; //k是处理左、右子树的标记 T ch; cin >> ch; while (ch != RefValue) { switch (ch) { case '(': //对(做处理 s.push(p); k = 1; break; case ')': //对)做处理 s.pop(); break; case ',': //对,做处理 k = 2; break; default: p = new BinTreeNode<T>(ch); //构造一个结点 if (BT == NULL) //如果头节点是空 { BT = p; } else if (k == 1) //链入*t的左孩子 { t = s.top(); t->leftChild = p; } else //链入*t的右孩子 { t = s.top(); t->rightChild = p; } } cin >> ch; } } //创建二叉树(利用已知的二叉树的前序遍历创建)用'#'表示空结点 void CreateBinTree_PreOrder(BinTreeNode<T> *&subTree) { T item; if (cin >> item) { if (item != RefValue) { subTree = new BinTreeNode<T>(item); //构造结点 if (subTree == NULL) { cout << "空间分配错误!" << endl; exit(1); } CreateBinTree_PreOrder(subTree->leftChild); //递归创建左子树 CreateBinTree_PreOrder(subTree->rightChild); //递归创建右子树 } else { subTree = NULL; } } } //使用先序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Pre_In(BinTreeNode<T> *&cur, const char *pre, const char *in, int n) { if (n <= 0) { cur = NULL; return; } int k = 0; while (pre[0] != in[k]) //再中序中找到pre[0]的值 { k++; } cur = new BinTreeNode<T>(in[k]); //创建结点 CreateBinTreeBy_Pre_In(cur->leftChild, pre + 1, in, k); CreateBinTreeBy_Pre_In(cur->rightChild, pre + k + 1, in + k + 1, n - k - 1); } //使用后序遍历和中序遍历创建二叉树 void CreateBinTreeBy_Post_In(BinTreeNode<T> *&cur, const char *post, const char *in, int n) { if (n == 0) { cur = NULL; return; } char r = *(post + n - 1); //根结点值 cur = new BinTreeNode<T>(r); //构造当前结点 int k = 0; const char *p = in; while (*p != r) { k++; p++; } CreateBinTreeBy_Post_In(cur->leftChild, post, in, k); CreateBinTreeBy_Post_In(cur->rightChild, post + k, p + 1, n - k - 1); } //二叉树的先序遍历(递归) void PreOrder(BinTreeNode<T> *&subTree) { if (subTree != NULL) { cout << subTree->data << " "; PreOrder(subTree->leftChild); PreOrder(subTree->rightChild); } } //二叉树的中序遍历(递归) void InOrder(BinTreeNode<T> *&subTree) { if (subTree != NULL) { InOrder(subTree->leftChild); cout << subTree->data << " "; InOrder(subTree->rightChild); } } //二叉树的后序遍历(递归) void PostOrder(BinTreeNode<T> *&subTree) { if (subTree != NULL) { PostOrder(subTree->leftChild); PostOrder(subTree->rightChild); cout << subTree->data << " "; } } //二叉树先序遍历(非递归1) void PreOrder_NoRecurve1(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; S.push(NULL); //最先push一个NULL,到最后一个结点没有左右子树时,栈里只有一个NULL了,令指针p指向这个NULL,再判断就会结束循环 while (p != NULL) { cout << p->data << " "; if (p->rightChild != NULL) //预留右子树指针在栈中 { S.push(p->rightChild); } if (p->leftChild != NULL) //进左子树 { p = p->leftChild; } else //左子树为空 { p = S.top(); S.pop(); } } } //二叉树先序遍历(非递归2) void PreOrder_NoRecurve2(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; BinTreeNode<T> *t; S.push(p); //根节点进栈 while (!S.empty()) //当栈不为空 { t = S.top(); //p先记住栈顶元素,然后栈顶出栈 S.pop(); cout << t->data << " "; //访问元素 if (t->rightChild != NULL) //右孩子不为空,右孩子近栈 { S.push(t->rightChild); } if (t->leftChild != NULL) //左孩子不为空,左孩子进栈 { S.push(t->leftChild); } } } //二叉树的中序遍历(非递归) void InOrder_NoRecurve(BinTreeNode<T> *p) { stack<BinTreeNode<T> *> S; do { while (p != NULL) { S.push(p); p = p->leftChild; } if (!S.empty()) { p = S.top(); S.pop(); cout << p->data << " "; p = p->rightChild; } } while (p != NULL || !S.empty()); } //二叉树的后序遍历(非递归) void PostOrder_NoRecurve(BinTreeNode<T> *p) { if (root == NULL) return; stack<BinTreeNode<T> *> s; s.push(p); BinTreeNode<T> *lastPop = NULL; while (!s.empty()) { while (s.top()->leftChild != NULL) s.push(s.top()->leftChild); while (!s.empty()) { //右叶子结点 || 没有右结点 if (lastPop == s.top()->rightChild || s.top()->rightChild == NULL) { cout << s.top()->data << " "; lastPop = s.top(); s.pop(); } else if (s.top()->rightChild != NULL) { s.push(s.top()->rightChild); break; } } } } //二叉树的层次遍历(非递归遍历) void LevelOrder(BinTreeNode<T> *p) { queue<BinTreeNode<T> *> Q; Q.push(p); //根节点进队 BinTreeNode<T> *t; while (!Q.empty()) { t = Q.front(); //t先记住队头,再将队头出队 Q.pop(); cout << t->data << " "; //访问队头元素的数据 if (t->leftChild != NULL) { Q.push(t->leftChild); } if (t->rightChild != NULL) { Q.push(t->rightChild); } } } //从结点subTree开始,搜索结点current的父节点,找到返回父节点的地址,找不到返回NULL BinTreeNode<T> *Parent(BinTreeNode<T> *subTree, BinTreeNode<T> *current) { if (subTree == NULL) { return NULL; } if (subTree->leftChild == current || subTree->rightChild == current) //如果找到,返回父节点subTree { return subTree; } BinTreeNode<T> *p; if (p = Parent(subTree->leftChild, current) != NULL) //递归在左子树中搜索 { return p; } else { return Parent(subTree->rightChild, current); //递归右子树中搜索 } } //二叉树的销毁 void Destroy(BinTreeNode<T> *&subTree) { if (subTree != NULL) { Destroy(subTree->leftChild); Destroy(subTree->rightChild); delete subTree; subTree = NULL; } } //复制二叉树,返回一个指针,给出一个以originNode为根复制的二叉树的副本 BinTreeNode<T> *Copy(BinTreeNode<T> *originNode) { if (originNode == NULL) { return NULL; } BinTreeNode<T> *temp = new BinTreeNode<T>; //创建根结点 temp->data = originNode->data; temp->leftChild = Copy(originNode->leftChild); temp->rightChild = Copy(originNode->rightChild); return temp; } //判断两颗二叉树是否相等 bool equal(BinTreeNode<T> *a, BinTreeNode<T> *b) { if (a == NULL && b == NULL) //两者都为空 { return true; } if (a != NULL && b != NULL && a->data == b->data && equal(a->leftChild, b->leftChild) && equal(a->rightChild, b->rightChild)) //两者都不为空,且两者的结点数据相等,且两者的左右子树的结点都相等 { return true; } return false; } //计算二叉树以subTree为根的结点的个数 int Size(BinTreeNode<T> *subTree) const { if (subTree == NULL) //递归结束,空树结点个数为0 { return 0; } return 1 + Size(subTree->leftChild) + Size(subTree->rightChild); } //计算二叉数以subTree为根的高度 int Height(BinTreeNode<T> *subTree) { if (subTree == NULL) //递归结束,空树高度为0 { return 0; } int i = Height(subTree->leftChild); int j = Height(subTree->rightChild); return i < j ? j + 1 : i + 1; } //以广义表的形式输出二叉树 void PrintBinTree(BinTreeNode<T> *BT) { if (BT != NULL) //树为空时结束递归 { cout << BT->data; if (BT->leftChild != NULL || BT->rightChild != NULL) { cout << '('; if (BT->leftChild != NULL) { PrintBinTree(BT->leftChild); } cout << ','; if (BT->rightChild != NULL) { PrintBinTree(BT->rightChild); } cout << ')'; } } } //翻转二叉树 void InvertTree(BinTreeNode<T> *originNode) { if (originNode == NULL) return; BinTreeNode<T> *tempNode = originNode->leftChild; originNode->leftChild = originNode->rightChild; originNode->rightChild = tempNode; InvertTree(originNode->leftChild); InvertTree(originNode->rightChild); } private: BinTreeNode<T> *root; //根节点 T RefValue; //数据输入停止的标志,需要一个构造函数 }; int main() { //构造二叉树时指定二叉树的结束标志为 # BinaryTree<char> tree('#'); //通过广义表创建二叉树 // tree.CreateBinTree(); //input: A(B(D,E(G,)),C(,F))# // tree.PrintBinTree(); //print: A(B(D,E(G,)),C(,F)) // cout << endl; //通过前序遍历创建二叉树 // tree.CreateBinTree_PreOrder(); // input: ABD##EG###C#F## // tree.PrintBinTree(); // print: A(B(D,E(G,)),C(,F)) //使用前序遍历和中序遍历创建二叉树 // tree.CreateBinTreeBy_Pre_In("ABDEGCF", "DBGEACF"); // tree.PrintBinTree(); // print: A(B(D,E(G,)),C(,F)) // cout << endl; //使用后序遍历和中序遍历创建二叉树 // tree.CreateBinTreeBy_Post_In("DGEBFCA", "DBGEACF"); // tree.PrintBinTree(); // print: A(B(D,E(G,)),C(,F)) // cout << endl; //二叉树的先序遍历(递归) // tree.PreOrder(); // print: A B D E G C F // cout << endl; //二叉树的中序遍历(递归) // tree.InOrder(); // print: D B G E A C F // cout << endl; //二叉树的后序遍历(递归) // tree.PostOrder(); // print: D G E B F C A // cout << endl; //二叉树先序遍历(非递归1) // tree.PreOrder_NoRecurve1(); // print: A B D E G C F //二叉树先序遍历(非递归2) // tree.PreOrder_NoRecurve2(); // print: A B D E G C F //中序遍历(非递归) // tree.InOrder_NoRecurve(); // print: D B G E A C F //二叉树的后序遍历(非递归) // tree.PostOrder_NoRecurve(); // print: D G E B F C A //二叉树的层次遍历(非递归) // tree.LevelOrder(); // print: A B C D E F G //二叉树的Size // cout << tree.Size() << endl; // print: 7 //二叉树的销毁 // tree.Destroy(); // cout << tree.Size() << endl; // print: 0 //二叉树是否为空 // cout << tree.Empty() << endl; // print: 1 //二叉树的高度 // cout << tree.Height() << endl; // print: 4 //拷贝二叉树 // BinaryTree<char> tree2 = tree; // tree2.PrintBinTree(); // print: A(B(D,E(G,)),C(,F)) //判断两颗二叉树是否相等 // cout << (tree2 == tree) << endl; // print: 1 //翻转二叉树 // tree2.InvertTree(); // tree2.PrintBinTree(); //print: A(C(F,),B(E(,G),D)) return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。