本贴为《数据结构》课程服务.
1. 主要内容
- 二叉树的层次遍历.
- 使用队列
2. 代码
2.1 李毛毛
说明:
- 几种遍历方式集成在一个程序里, 我就偷懒没把它们分开.
- 队列应该叫做 enqueue, dequeue, 栈的操作才是 push, pop.
// 李毛毛
#include<iostream>
#include<cstdlib>
#include<stack>
#include<queue>
using namespace std;
typedef struct BinTreeNode
{
char data;
struct BinTreeNode *leftChild;
struct BinTreeNode *rightChild;
}*myTree;
//函数申明
void CreateBinTree(myTree tree);
//二叉树递归遍历
void preorderTraversal(myTree tree); //(中左右)
void inorderTraversal(myTree tree); //(左中右)
void orderTraversal(myTree tree); //(右中左)
//二叉树的栈(非递归)遍历
void PreOrder_NoRecurve1(myTree p); //先序遍历
void InOrder_NoRecurve(myTree p); //中序遍历
void PostOrder_NoRecurve(myTree p); //后序遍历
//二叉树的队列(非递归)遍历
void LevelOrder(myTree p);
int main()
{
cout<<"请输入你要创建的二叉树(以#结束):";
myTree root = NULL;
CreateBinTree(root);
return 0;
}
//使用广义表创建二叉树函数,这里以“字符”创建二叉树,以'#'字符代表结束
void CreateBinTree(myTree root)
{
stack<myTree> s;
int k; //k是处理左、右子树的标记
myTree p,t; //p用来记住当前创建的节点,t用来记住栈顶的元素
char ch;
cin>>ch;
while(ch != '#')
{
switch(ch)
{
case '(': //对(做处理
s.push(p);
k=1;
break;
case ')': //对)做处理
s.pop();
break;
case ',': //对,做处理
k=2;
break;
default:
p = (myTree)malloc(sizeof(BinTreeNode)); //构造一个结点
p->leftChild = NULL;
p->rightChild = NULL;
if (root == NULL) //如果头节点是空
{
root = p;
p->data = ch;
}
else if (k == 1) //链入*t的左孩子
{
t = s.top();
t->leftChild = p;
p->data = ch;
}
else //链入*t的右孩子
{
t = s.top();
t->rightChild = p;
p->data = ch;
}
}
cin>>ch;
}
cout<<endl<<"采用递归遍历二叉树"<<endl;
cout<<"使用中左右输出:";
preorderTraversal(root);
cout<<endl;
cout<<"使用左中右输出:";
inorderTraversal(root);
cout<<endl;
cout<<"使用左右中输出:";
orderTraversal(root);
cout<<endl<<endl<<"采用栈遍历二叉树:"<<endl;
cout<<"使用先序输出:";
PreOrder_NoRecurve1(root);
cout<<endl;
cout<<"使用中序输出: ";
InOrder_NoRecurve(root);
cout<<endl;
cout<<"使用后序输出:";
PostOrder_NoRecurve(root);
cout<<endl;
cout<<endl<<"采用层次遍历(队列)二叉树:" <<endl;
LevelOrder(root);
cout<<endl;
}
/*myTree constructABinaryTree() { //创建一个二叉树
myTree root = (myTree)malloc(sizeof(BinTreeNode));
root->data = 5;
root->leftChild = NULL;
root->leftChild = NULL;
myTree leftChild = (myTree)malloc(sizeof(BinTreeNode));
leftChild->data = 7;
leftChild->leftChild = NULL;
leftChild->rightChild = NULL;
root->leftChild = leftChild;
myTree rightChild = (myTree)malloc(sizeof(BinTreeNode));
rightChild->data = 6;
rightChild->leftChild = NULL;
rightChild->rightChild = NULL;
root->rightChild = rightChild;
myTree twoLeftChild = (myTree)malloc(sizeof(BinTreeNode));
twoLeftChild->data = 4;
twoLeftChild->leftChild = NULL;
twoLeftChild->rightChild = NULL;
leftChild->leftChild = twoLeftChild;
myTree leftRightChild = (myTree)malloc(sizeof(BinTreeNode));
leftRightChild->data = 3;
leftRightChild->leftChild = NULL;
leftRightChild->rightChild = NULL;
leftChild->rightChild = leftRightChild;
return root;
}*/
void preorderTraversal(myTree tree)
{
cout << tree->data << " ";
if (tree->leftChild != NULL) preorderTraversal(tree->leftChild);
if (tree->rightChild != NULL)preorderTraversal(tree->rightChild); //中左右
}
void inorderTraversal(myTree tree)
{
if (tree->leftChild != NULL) inorderTraversal(tree->leftChild); //左中右
cout << tree->data << " ";
if (tree->rightChild != NULL)inorderTraversal(tree->rightChild);
}
void orderTraversal(myTree tree) //左右中、
{
if (tree->leftChild != NULL) orderTraversal(tree->leftChild);
if (tree->rightChild != NULL)orderTraversal(tree->rightChild);
cout << tree->data<<" ";
}
void PreOrder_NoRecurve1(myTree p) //先序遍历
{
stack<myTree> 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();
}
}
}
void InOrder_NoRecurve(myTree p) //中序遍历
{
stack<myTree> 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(myTree p) //后序遍历
{
if (p == NULL)
return ;
stack<myTree> s;
s.push(p);
myTree 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(myTree p) //队列层次遍历
{
queue<myTree> Q;
Q.push(p); //根节点进队
myTree 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);
}
}
}
2.2 付乐兵
助教辜果推荐.
//付乐兵,202031061023,计算机类1班
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define MAXSIZE 100
#define TRUE 1
#define FALSE 0
#define YES 1
#define NO 0
#define ERROR 0
#define SUCCESS 1
typedef int QElemType;
typedef int Status;
typedef char TElemType;
typedef char ElemType;
typedef struct BiTNode
{
TElemType data; //结点元素
struct BiTNode *lchild; //左孩子指针
struct BiTNode *rchild; //右孩子指针
} BiTNode,*BiTree;
//-----------------------//
typedef struct StackNode
{
BiTree Stack_data; //栈的数据域存放树的结点
struct StackNode *next;
} StackNode,*LinkStack;
//-----------------------//
typedef struct QNode
{
BiTree QT; //数据域存放树的结点
struct QNode *next;
} QNode,*QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
} LinkQueue;
//----------------------//
LinkStack InitStack(LinkStack &S); //初始化
bool StackEmpty(LinkStack S); //判空
void Push(LinkStack &S,BiTree e); //入栈
BiTree Pop(LinkStack S); //出栈
//-----------------------------------//
void InitBiTree(BiTree &T);
//构造空二叉树T
BiTree CreateBiTree(BiTree &T);
//创建二叉树
Status BiTreeEmpty(BiTree T);
//判断二叉树是否为空
BiTree frontNode(BiTree T);
//后序时前驱节点
void PreOrderTraverse(BiTree T);
//非递归算法先序遍历二叉树
void InOrderTraverse(BiTree T);
//非递归算法中序遍历二叉树
void PostOrderTraverse(BiTree T);
//非递归算法后序遍历二叉树
void LevelOrderTraverse(BiTree T);
//层序遍历二叉树
//---------------------//
void InitQueue(LinkQueue &Q);
//构造一个空队列Q
void EnQueue(LinkQueue &Q,BiTree T);
//入队
BiTree DeQueue(LinkQueue &Q);
//出队
//---------------------//
int main()
{
BiTree T;
InitBiTree(T);
printf("测试样例:1,2,4,#,#,5,#,#,3,6,#,#,7,#,#\n");
printf("请输入头结点:");
CreateBiTree(T);
printf("前序遍历\n");
PreOrderTraverse(T);
printf("\n");
printf("中序遍历\n");
InOrderTraverse(T);
printf("\n");
printf("后序遍历\n");
PostOrderTraverse(T);
printf("\n");
printf("队列实现层次遍历\n");
LevelOrderTraverse(T);
}
LinkStack InitStack(LinkStack &S)
{
S=(StackNode*)malloc(sizeof(StackNode*));
S->next=NULL;
return S;
}
void Push(LinkStack &S,BiTree e)
{
if(e) //若树不为空
{
StackNode *p=(StackNode *)malloc(sizeof(StackNode));
p->Stack_data=e;
p->next=S->next;
S->next=p;
}
}
bool StackEmpty(LinkStack S)
{
if(S==NULL)
return false;
else
return S->next==NULL;
}
BiTree Pop(LinkStack S)
{
if(StackEmpty(S))
{
printf("Stack is empty!\n");
return NULL;
}
BiTree mid = S->next->Stack_data;
LinkStack p = S->next;
S->next = p->next;
free(p);
return mid;
}
//----------------------------------------//
void InitBiTree(BiTree &T)//构造空二叉树T
{
T = NULL;
printf("初始化成功!\n");
return ;
}
BiTree CreateBiTree(BiTree &T)//创建二叉树
{
TElemType ch;
scanf("%c",&ch);
getchar(); //吃掉回车键
if(ch == '#') //若输入#表示该位置为NULL
return NULL;
T = (BiTree)malloc(sizeof(BiTNode)); //分配树结点
if(!T)
printf("失败\n");
T->data = ch;
printf("请输入%c的左子树:",T->data);
T->lchild= CreateBiTree(T->lchild);
printf("请输入%c的右子树:", T->data);
T->rchild = CreateBiTree(T->rchild);
return T;
}
Status BiTreeEmpty(BiTree T)//判断二叉树是否为空
{
if(T==NULL)
return TRUE;
else
return FALSE;
}
BiTree frontNode(BiTree T)
{
if (T->rchild)
return T->rchild;
return T->lchild;
}
void PreOrderTraverse(BiTree T)//栈实现先序遍历二叉树
{
LinkStack stackTop;
InitStack(stackTop);
while(T)
{
//从根开始,往左遍历到头
while(T)
{
printf("%c ", T->data); //遇到结点就输出
Push(stackTop,T->rchild); //将该节点的右节点进行压栈,压栈操作会自己判断数据是否有效
T = T->lchild; //依次输出左节点
}
if (!StackEmpty(stackTop)) //若栈不为空
T = Pop(stackTop); //最近的右结点出栈
}
}
void InOrderTraverse(BiTree T) //堆栈实现中序遍历
{
LinkStack stackTop;
InitStack(stackTop);
while(T || !StackEmpty(stackTop))
{
while(T)
{
Push(stackTop, T);
T = T->lchild;
}
if (!StackEmpty(stackTop))
{
T = Pop(stackTop);
printf("%c ", T->data);
T = T->rchild;
}
}
}
void PostOrderTraverse(BiTree T)//栈后序遍历二叉树
{
LinkStack stackTop;
InitStack(stackTop);
BiTree last = NULL;
while(T || !StackEmpty(stackTop))
{
while(T) //遍历左子树压栈
{
Push(stackTop, T);
T = T->lchild;
}
if (!StackEmpty(stackTop))
{
BiTree judge = stackTop->next->Stack_data->rchild;
if (judge)
{
T = judge; //判断是否有右子节点,有就把它当做子树的根节点先行遍历
}
else
{
last = Pop(stackTop); //如果没有右子节点,那说明为叶子节点,出栈
printf("%c ", last->data);
while(!StackEmpty(stackTop) && last == frontNode(stackTop->next->Stack_data))
{
//当弹出一个叶子节点之后,需要将前驱节点已经弹出的全部都弹出
last = Pop(stackTop);
printf("%c ", last->data);
}
T = NULL; //弹出前面的节点以后,说明该子树已经遍历完,不再进行重复遍历
}
}
}
}
void InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));//此处不用->要用.
if(!Q.front) exit(OVERFLOW);
Q.front->next=NULL;
}
void EnQueue(LinkQueue &Q,BiTree T) //入队
{
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if(p == NULL)
exit(0);
else
{
p->QT = T;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return ;
}
}
BiTree DeQueue(LinkQueue &Q) //出队
{
QueuePtr p = Q.front->next;
if(Q.front == Q.rear)
return NULL;
Q.front->next = p->next;
if(Q.rear == p)
Q.rear = Q.front;
return p->QT;
}
void LevelOrderTraverse(BiTree T)//层序遍历二叉树
{
BiTree t = NULL;
LinkQueue Q;
InitQueue(Q);
if(T != NULL)
EnQueue(Q,T); //若树不空,让根节点入队
else
return;
while(Q.front != Q.rear) //队列不空
{
t = DeQueue(Q); //元素出队
printf("%c ",t->data);
if(t->lchild != NULL) //判断子左子树是否为空
EnQueue(Q,t->lchild); //不空则让它入队
if(t->rchild != NULL) //判断子右子树是否为空
EnQueue(Q,t->rchild); //不空则让它入队
}
printf("\n");
return;
}
3. 建议与意见
来拍砖吧!