Data-Structure11

Before:全世界都在偶遇她,只有我没机会嘛😥

Data Structure 11 二叉链表遍历的非递归实现及二叉树的应用

二叉链表遍历的非递归实现

上一节翁阿姨的课上,我们讲到了通过栈对函数实现非递归调用,而今天所说的二叉链表遍历的非递归实现,同样也是依靠链接栈这一数据结构实现的。实现时需要注意进栈顺序的细节,下面给出代码实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T>
void binaryTree<T>::preOrder() const{
linkStack<Node *> s;
s.push(root);
while(!s.isEmpty()){
Node *tmp = s.pop();
cout << tmp -> data;

if(tmp -> left != nullptr){
s.push(tmp -> left);
}
if(tmp -> right != nullptr){
s.push(tmp -> right);
}
}
}

而中序遍历在实现时则有一些不同,因为中序遍历要求先访问左子树,再访问根结点,最后访问右子树,所以在根结点出栈后不能先访问它,而将其暂存,先访问左子树,再访问它。为了解决这一问题,我们重新更换一种结点,记录结点进栈的次数。

1
2
3
4
5
6
7
8
struct StNode{
Node *node;
int timePop;
StNode(Node *n = nullptr){
node = n;
timePop = 0;
};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <class T>
void binaryTree<T>::midOrder() const{
linkStack<StNode> s;
StNode current(root);

while(!s.isEmpty()){
current = s.pop();
++ current.timePop;
if(current.timePop == 2){
// 出栈2次了
cout << current.node -> data << endl;
if(current.node -> right != nullptr){
current.push(StNode n(current.node -> right));
}
}else{
// 重新被推回栈中
s.push(current);
if(current.node -> left != nullptr){
current.push(StNode n(current.node -> left));
}
}
}
}

最后是后序遍历,与中序遍历实现方法类似,但只有在第三次出栈时才会被访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template <class T>
void binaryTree<T>::postOrder() const{
linkStack<StNode> s;
StNode current(root);

while(!s.isEmpty()){
current = s.pop();
++ current.timePop;

if(current.timePop == 3){
cout << current.node -> data << endl;
}else if(current.timePop == 2){
s.push(current);
if(current.node -> right != nullptr){
s.push(StNode n(current.node -> right));
}
}else if(current.timePop == 1){
s.push(current);
if(current.node -> left != nullptr){
s.push(StNode n(current.node -> left));
}
}
}
}

二叉树的应用——计算表达式

由于算术运算符是二元运算符,故可以很自然地表示成一棵二叉树,根结点表示运算符,左右孩子是运算数,这棵树被称为表达式树,既然如此,我们知道对这棵树的遍历是后序遍历
下面就是一棵表达式树:
表达式树

所描述的表达式为:**(4 - 2)(10 + (4 + 6)/2) + 2*

这个逻辑构造似乎还是比较好理解的,所以,我们就直接来看看如何建树吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class calc{
enum Type{DATA,ADD,SUB,MULTI,DIV,OPAREN,CPAREN,EOL};

struct node{
Type type;
int data;
node *lchild,rchild;

node(Type t,int d = 0,node *lc = nullptr,node *rc = nullptr){
type = t;
data = d;
lchild = lc;
rchild = rc;
}
};

node *root;

node *create(char *&s); //创建一棵表达式树
Type getToken(char *&s,int &value); // 获得一个切片
int result(node *t); //计算表达式结果

public:
calc(char *s){
root = create(s);
}

int result(){
if(root == nullptr){
return 0;
}
return result(root);
}
};

create函数的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
calc::node *calc::create(char *&s){
calc::node *p,*root = nullptr;
Type returnType;
int value;

while(*s){
returnType = calc::getToken(s,value);

switch(returnType){
case DATA:case OPAREN:
if(returnType == DATA){
node *p = new node(DATA,value);
}else{
p = create(s);
}
if(root != nullptr){
if(root -> rchild == nullptr){
root -> rchild = p;
}else{
root -> rchild -> rchild = p;
}
}
break;
case ADD: case SUB:
if(root == nullptr){
root = new node(returnType,0,p);
}else{
root = new node(returnType,0,root);
}
break;
case MULTI: case DIV:
if(root == nullptr){
root = new node(returnType,0,p);
}else if(root -> type == MULTI || root -> type == DIV){
root = new node(returnType,0,root);
}else{
root -> rchild = new node(returnType,0,root -> rchild);
}
break;
case CPAREN: caseEOL:
return root;
}
}
return root;
}

getToken 函数与先前在Bookstore-2024中写的TokenScanner类类似,故不描述了(好懒啊😅)

另一个比较有趣的函数——result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int calc::result(calc::node *t){
int num1,num2;
if(t -> type == DATA){
return t -> data;
}
num1 = calc(t -> lchild);
num2 = calc(t -> rchild);
if(t -> type == ADD){
t -> data = num1 + num2;
return num1 + num2;
}else if(t -> type == SUB){
t -> data = num1 - num2;
return num1 - num2;
}else if(t -> type == MULTI){
t -> data = num1 * num2;
return num1 * num2;
}else if(t -> type == DIV){
t -> data = num1 / num2;
return num1 / num2;
}
}

Conclude

这两天一直在写二叉树,总结一下,真是对递归很巧妙的应用呢!
下面就是Huffman Tree了,离priority_queue越来越近了😝


Data-Structure11
http://example.com/2025/02/25/Data-Structure11/
Author
Yihan Zhu
Posted on
February 25, 2025
Updated on
February 26, 2025
Licensed under