操作包含:
1.二叉树的构造(先序序列和中序序列,中序序列和后序序列)
2.利用三种遍历方式输出(先序遍历,中序遍历,后序遍历,层次遍历)每种遍历包含递归和非递归两种算法。
3.栈和队列的构造(C++)模板,均为顺序存储结构
main.cpp
1.构造二叉树。
确认中序和先序 ,或者中序和后序可以确定树的结构。
1.构造二叉树的思想:
中序可以确立某个子树的根节点的左右子树中分别的结点数,而先序和后序是用于确定结点的值。而二叉树中,从上至下,从根结点 ,确认左子树结点 右子树结点,确认左子树结点的子树的左右结点 右子树结点的左右结点……这就是递归的思想。
2.创建二叉树的思路:
建立结点,输入结点的数据。(结点数据需要在先序或者后序中找到)
找到根节点之后,根节点的左右结点也就是子树的根节点,与找整个树的根节点的思路相同,可以采用递归。
递归的尽头在于形参中的第三个数据,即结点数量。结点数量小于零时返回空。
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "queue.h"
//1.create a binary tree;
typedef struct BNode {
char data;//data
struct BNode*lchild;
struct BNode*rchild;
} BTree;
void InitBTree(BTree*&b) {
b->data = 0;
b->lchild = b->rchild = NULL;
}
//先序序列和中序序列建立二叉树
//先序 中序 结点个数
//利用先序找到每个子树中的根节点,然后赋值*pre,in和n则是为了确立子树的位置
//利用树到子树的一般规律完成递归算法
BTree* CreateBTree1(char*pre, char* in, int n) {
if (n <= 0) { //为空时返回空
return NULL;
}
BNode *b;//结点的建立
b = (BNode*)malloc(sizeof(BNode));
b->data = *pre;
char*p;//in中的*pre的类型
for (p = in; p < in + n; p++) {
if (*p == *pre) {
break;
}
}
int k = p - in; //k根结点的位置
b->lchild = CreateBTree1(pre + 1, in, k); //递归左子树
b->rchild = CreateBTree1(pre + k + 1, p + 1, n - k - 1); //递归右子树
return b;
}
//后序和先序的不同在于根节点在最后
BTree* CreateBTree2(char *in, char *post, int n) {
if (n <= 0) {
return NULL;
}
char r = *(post + n - 1);
BNode *b;
b = (BNode*)malloc(sizeof(BNode));
b->data = r;
char*p;
for (p = in; p < in + n; p++) {
if (*p == r) {
break;
}
}
int k = p - in;
b->lchild = CreateBTree2(in, post, k);
b->rchild = CreateBTree2(p + 1, post + k, n - k - 1);
return b;
}
2.输出二叉树,先序(递归一种,非递归两种),中序(递归一种,非递归一种),后序(递归一种,非递归一种),层次(非递归一种)
1.递归思想:每个结点都会遍历三次,差别在于在第几次遍历时输出。
非递归:见代码注释。
//输出
//递归算法
void PreOrder1(BTree *b) {
if (b != NULL) {
printf("%c", b->data); //访问输出第一个结点的值
PreOrder1(b->lchild);//遍历左子树
PreOrder1(b->rchild);//遍历右子树
}
}
void InOrder1(BTree *b) {
if (b != NULL) {
InOrder1(b->lchild);
printf("%c", b->data);
InOrder1(b->rchild);
}
}
void PostOrder1(BTree *b) {
if (b != NULL) {
PostOrder1(b->lchild);
PostOrder1(b->rchild);
printf("%c", b->data);
}
}
//非递归算法
//先序遍历
void PreOrder2(BTree *b)
//根左右,需要保存根的地址以防止丢失,可用栈保存,因为右结点先保存后用
{
//利用栈的特点:先进后出
//自上而下,将需要存储的直接存储
//存储一个右节点 一个左节点 (循环)每次循环输出上次左节点时将其出栈
BNode *p;
stack<BTree*>s;
if (b != NULL) {
s.push(b);
while (!s.empty()) {
p = s.top();
s.pop();
printf("%c", p->data);
if (p->rchild != NULL) {
s.push(p->rchild);
}
if (p->lchild != NULL) {
s.push(p->lchild);
}
}
printf("\n");
}
}
void PreOrder3(BTree *b) {
//先存储所有左节点,然后到最底端时处理右子树,往上走出栈处理另外一层左子树的右子树
BNode *p;
p = b;
stack<BTree*>s;
while (!s.empty() || p != NULL) {
while (p != NULL) {
printf("%c", p->data);
s.push(p);
p = p->lchild;
}
if (!s.empty()) {
p = s.top();
s.pop();
p = p->rchild;
}
}
printf("\n");
}
//中序遍历
void InOrder2(BTree *b) {
//与PreOrder3的不同是在回去的时候访问结点,为左根右
BNode *p;
p = b;
stack<BTree*>s;
while (!s.empty() || p != NULL) {
while (p != NULL) {
s.push(p);
p = p->lchild;
}
if (!s.empty()) {
p = s.top();
printf("%c", p->data);
s.pop();
p = p->rchild;
}
}
printf("\n");
}
//后序遍历
void PostOrder2(BTree *b) {
//后序遍历和中序遍历的不同在于要将左右子树都遍历玩成后才能访问根节点并且退栈
BTree*p, *r;
bool flag;
stack<BTree*>s;
p = b;
do {
//将所有左结点进栈
//将右孩子进栈
while (p != NULL) {
s.push(p);
p = p->lchild;
}
r = NULL; //判断是否遍历过
flag = true; //判断是否为栈顶结点
while (!s.empty() && flag) {
p = s.top();
if (p->rchild == r) {//看右子树是否被遍历过
printf("%c", p->data);
r = s.top();
s.pop();//遍历过就输出结点出栈
} else {
p = p->rchild;
flag = false;//未遍历就退出这个循环处理右孩子
}
}
} while (!s.empty());
printf("\n");
}
//层次遍历
void LevelOrder(BTree*b) {
BTree*p;
queue<BTree*>q;
q.push(b);
while (!q.empty()) {
p = q.front();
q.pop();
printf("%c", p->data);
if (p->lchild != NULL) {
q.push(p->lchild);
}
if (p->rchild != NULL) {
q.push(p->rchild);
}
}
}
3.main()函数运行
int main() {
int length = 7;
// char pre[10] = "ABDGCEF";
char in[10] = "DGBAECF";
char post[10] = "GDBEFCA";
BTree *BT;
// BT = CreateBTree1(pre,in,length);
BT = CreateBTree2(in, post, length);
printf("先序遍历: \n" );
PreOrder1(BT);
printf("\n");
PreOrder2(BT);
PreOrder3(BT);
printf("\n中序遍历: \n");
InOrder1(BT);
printf("\n");
InOrder2(BT);
printf("\n后序遍历: \n");
PostOrder1(BT);
printf("\n");
PostOrder2(BT);
printf("\n层次遍历: \n");
LevelOrder(BT);
return 0;
}
附:queue和stack的顺序存储(模板class)
stack.h类模板 顺序存储结构
#ifndef _STACK_H_
#define _STACK_H_
#define MAX 100
template<class ElemType>
class stack {
public:
stack() {
this->length = -1;
}
~stack() {
delete[]this->data;
}
bool empty() const;
void push(const ElemType& ET);
void pop();
ElemType top() const;
ElemType* data = new ElemType[MAX];
//top类似于线性表中的length的作用
//线性表和栈在顺序上
int length;
};
template<class ElemType>
bool stack<ElemType>::empty() const {
return this->length == -1;
}
template<class ElemType>
void stack<ElemType>::push(const ElemType& ET) {
if (this->length != MAX - 1) {
this->data[++this->length] = ET;
}
}
template<class ElemType>
void stack<ElemType>::pop() {
if (this->length != -1) {
this->length--;
}
}
template<class ElemType>
ElemType stack<ElemType>::top() const {
return this->data[this->length];
}
#endif
queue.h 类模板 链式存储结构
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <iostream>
template<class ElemType>
class queue {
public:
queue();
~queue();
bool empty() const;
void push(const ElemType& e);
void pop();
ElemType front() const;
private:
struct Node {
ElemType data;
Node*next;
Node(const ElemType& d, Node*n = nullptr): data(d), next(n) {};
};
Node*frnt;
Node*rear;
int size;
};
template<class ElemType>
queue<ElemType>::queue() {
this->frnt = this->rear = nullptr;
this->size = 0;
}
template<class ElemType>
queue<ElemType>::~queue() {
while (this->frnt != nullptr) {
Node*temp = this->frnt;
this->frnt = this->frnt->next;
delete temp;
}
}
template<class ElemType>
bool queue<ElemType>::empty() const {
return this->frnt == nullptr;
}
template<class ElemType>
void queue<ElemType>::push(const ElemType& e) {
Node *newNode = new Node(e);
if (this->empty()) {
this->frnt = this->rear = newNode;
} else {
this->rear->next = newNode;
this->rear = newNode;
}
this->size++;
}
template<class ElemType>
void queue<ElemType>::pop() {
if (!this->empty()) {
Node *temp = this->frnt;
this->frnt = this->frnt->next;
delete temp;
this->size--;
} else {
std::cout << "queue is empty!" << std::endl;
}
}
template<class ElemType>
ElemType queue<ElemType>::front() const {
if (!this->empty()) {
return this->frnt->data;
} else
return nullptr;
}
#endif