很多同学在学二叉树的建立,遍历的时候都是看书上的伪代码,虽然能理解,但是不知道怎么把这些伪代码转换成真正的代码运行,这里我们用代码建立二叉树,并用前序遍历输入构建二叉树,层次遍历,前序中序后序遍历依次输出,并计算节点数和叶子数,我们看程序输出的和理论的遍历是否一样。
我们建立一个上图所示这样的二叉树,它的前序遍历是ABDC,但是我们不能直接输入ABDC就建立这样的二叉树,因为如果只知道前序遍历,那所对应的的二叉树有很多种,那怎么解决呢?
我们把这个树扩展,没有左右节点的就用#填充,如下图
其中空节点我们输入“#”,其他节点输入对应的字母就行了,这样的二叉树的前序遍历是AB#D##C##,这样就可以确定唯一的二叉树了。
这个简单的二叉树层次遍历是ABCD,中序遍历是BDAC,后序遍历是DBCA。
在层次遍历的代码中,我们用了顺序存储结构的队列,层次遍历用队列输出的原理想必大家都知道,这里就不详细叙述了。
接下来就是写代码了
实现代码:
#include <iostream>
#include <cstdlib>
#include <string>
#define ERROR 0
#define OK 1
#define MAXSIZE 100
using namespace std;
typedef char ElemType;/*元素类型默认为char**/
typedef struct BiNode
{
ElemType data;
struct BiNode* lchild;
struct BiNode* rchild;
} BiNode, *BiTree;
typedef struct
{
BiTree *base;/*重点,队列里面的元素是节点的指针*/
int front;
int rear;
}Squeue;
int InitQueue(Squeue &Q)
{
Q.base = new BiTree[MAXSIZE];/*队列里面的元素是节点的指针*/
if (!Q.base) exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
bool isEmpty(const Squeue Q)/*判断队列是否为空*/
{
return Q.front == Q.rear;
}
bool isFull(const Squeue Q)
{
return (Q.rear + 1) % MAXSIZE == Q.front;
}
bool EnQueue(Squeue &Q, BiTree tree)/*入队*/
{
if (isFull(Q))
return ERROR;
Q.base[Q.rear] = tree;
Q.rear = (Q.rear + 1) % MAXSIZE;
return OK;
}
BiTree DeQueue(Squeue &Q)/*出队,并返回出队的元素*/
{
if (isEmpty(Q))
return ERROR;
BiTree e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXSIZE;
return e;
}
BiTree CreatTree(BiTree tree)/*按照前序遍历的顺序输入,如果没有节点就用#,有节点就用字母*/
{
ElemType ch;
cin >> ch;
if (ch == '#') return NULL;/*如果是*,说明节点为空*/
else
{
tree = new BiNode;
tree->data = ch;
tree->lchild = CreatTree(NULL);
tree->rchild = CreatTree(NULL);
return tree;
}
}
void LevelOrderTraverse(BiTree tree)/*层次遍历*/
{
Squeue Q;
BiTree T;
InitQueue(Q);
if (tree == NULL) return;
EnQueue(Q, tree);
while (!isEmpty(Q))/*如果队列不为空,一直出队一个,然后把它的左右指针入队*/
{
T = DeQueue(Q);/*出队元素赋值给T*/
if (T != NULL)/*如果元素不是空指针*/
{
cout << T->data; /*输出节点的数据*/
EnQueue(Q, T->lchild);/*左孩子入队*/
EnQueue(Q, T->rchild);/*右孩子入队*/
}
}
}
void PreOrderTraverse(BiTree tree)/*前序遍历*/
{
if (tree == NULL) return;
cout << tree->data;
PreOrderTraverse(tree->lchild);
PreOrderTraverse(tree->rchild);
}
void InOrderTraverse(BiTree tree)/*中序遍历*/
{
if (tree == NULL) return;
PreOrderTraverse(tree->lchild);
cout << tree->data;
PreOrderTraverse(tree->rchild);
}
void PostOrderTraverse(BiTree tree)/*后序遍历*/
{
if (tree == NULL) return;
PostOrderTraverse(tree->lchild);
PostOrderTraverse(tree->rchild);
cout << tree->data;
}
int NodeCount(BiTree tree)/*计算节点数*/
{
if (tree == NULL) return 0;
else return (NodeCount(tree->lchild) + NodeCount(tree->rchild) + 1);
}
int yeCount(BiTree tree)/*计算叶子数*/
{
if (tree == NULL) return 0;
if (tree->lchild == NULL && tree->rchild == NULL)
return 1;
else return(yeCount(tree->lchild) + yeCount(tree->rchild));
}
void DeleteBiTree(BiTree &tree)/*删除叶子*/
{
if (tree->lchild)
DeleteBiTree(tree->lchild);
if (tree->rchild)
DeleteBiTree(tree->rchild);
cout << "删除的当前节点是 "<<tree->data << endl;
delete tree;
tree = NULL;
}
int main()
{
cout << "请输入字符" << endl;
BiTree root = CreatTree(NULL);
cout << "输入成功" << endl;
cout << "层次遍历:";
LevelOrderTraverse(root);
cout << endl;
cout << "前序遍历:";
PreOrderTraverse(root);
cout << endl;
cout << "中序遍历:";
InOrderTraverse(root);
cout << endl;
cout << "后序遍历:";
PostOrderTraverse(root);
cout<<endl;
cout<<"节点个数为:"<< NodeCount(root)<<endl;
cout<<"叶节点个数为:" << yeCount(root)<<endl;
cout << "删除中..." << endl;
DeleteBiTree(root);
if (root == NULL)
cout << "根节点为空,删除成功!" << endl;
system("pause");
}
测试结果:
和理论结果一样。
运行环境:Visual Studio 2017
参考书籍《大话数据结构》