数据结构实验二

学生实验报告

开课学院及实验室: 年 月 日
学院 年级、专业、班 姓名 学号
实验课程名称 数据结构 成绩
实验项目名称 实验二 二叉树的操作和实现 指导老师
评语:
一、实验目的
1.二叉树是一种最常用的数据结构,而满二叉树和完全二叉树又是两种特殊形态的树。普通二叉树具有三个性质,完全二叉树具有两个性质。掌握二叉树的五个性质。
2.掌握二叉树的链式存储方式。
3.掌握二叉树的先序,中序,后序遍历算法,掌握在三种基本遍历算法的基础上实现二叉树的其他算法。
4.在线索二叉树中,利用二叉链表中的n+1个空指针域来存放指向某种遍历次序下的前驱结点和后继结点的指针,这些附加的指针就称为线索。
5.掌握哈夫曼树和哈夫曼编码的构造算法。
6.、掌握森林与树的相互转换方法。
二、使用仪器、器材
微机一台
编程软件:C++

三、实验内容及原理
利用二叉树的二叉链式存储结构设计并实现各种操作算法。
1.二叉树的基本操作算法实现
(1)利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构;
(2)输出该二叉树;
(3)输出‘H’节点的左、右孩子结点值;
(4)输出该二叉树的结点个数、叶子结点个数、二叉树的度和高度;

根据广义表绘制出二叉树,并且求了树结点,叶子结点,树的度,以及树的高度
而二叉树的先序序列为:ABD##EHJ##KL##M#N##CF##G#I##
2.二叉树的各种遍历算法实现
实现上述二叉树的先序、中序和后序遍历的递归和非递归算法;
3.线索二叉树的遍历
中序线索化上述二叉树并找出根结点的前驱和后继。
4.构造哈夫曼树和哈夫曼编码的算法实现
统计下面一段英文的不同字符个数和每个字符的出现频率,利用统计数据构造构造哈夫曼树和哈夫曼编码
The Chinese official said he viewed the Trump Presidency not as an aberration but as the product of a failing political system. This jibes with other accounts. The Chinese leadership believes that the United States, and Western democracies in general, haven’t risen to the challenge of a globalized economy, which necessitates big changes in production patterns, as well as major upgrades in education and public infrastructure. In Trump and Trumpism, the Chinese see an inevitable backlash to this failure.

<简要描述具体任务;填写程序设计中使用的数据结构及算法(算法思路和程序框架)>

四、实验过程原始数据记录
1.二叉树的基本操作算法实现
1.利用二叉树字符串“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建二叉树的二叉链式存储结构;
2.输出该二叉树;
3.输出‘H’节点的左、右孩子结点值;
4.输出该二叉树的结点个数、叶子结点个数、二叉树的度和高度;
代码部分:
#include
#include
using namespace std;
typedef char TElemType;
#define MAXSIZE 100
typedef struct BiTNode
{
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode,BiTree;
typedef struct
{
int stacksize;
BiTree
base;
BiTree* top;
}SqStack;
int Push(SqStack& S, BiTree e)
{
if (S.top - S.base == S.stacksize)
{
return 0;
}
*S.top = e;
S.top++;
return 1;
}
int Pop(SqStack& S, BiTree& e)
{
if (S.top == S.base)
{
return 0;
}
else
{
–S.top;
e = *S.top;
return 1;
}

}
int StackEmpty(SqStack S)
{
if (S.top == S.base)
{
return 1;
}
else
{
return 0;
}
}
int InitStack(SqStack& S)
{
S.base = new BiTree[MAXSIZE];
if (S.base == 0)
{
return 0;
}
S.top = S.base;
S.stacksize = MAXSIZE;
}
void CreateTree(BiTree& T)
{
SqStack S;
InitStack(S);
int flag = 1;
BiTree p, q=NULL;
q = new BiTNode;
char ch;
while (cin>>ch)
{
if (ch != ‘#’)
{
p = new BiTNode;
p->data = ch;
p->lchild = p->rchild = NULL;
if (T == NULL)
{
T = p;
}
else
{
if (flag == 1)
{
q->lchild = p;
}
else
{
q->rchild = p;
}
}
q = p;
Push(S, q);
flag = 1;
}
else
{
Pop(S, q);
flag = 0;
}
}
}
int SearchBiTree_H(BiTree T)
{
if (T == NULL)
{
return 0;
}
else
{
if (T->data == ‘H’ && T->lchild != NULL && T->rchild != NULL)
{
cout << “H的左孩子是:” << T->lchild->data << endl;
cout << “H的右孩子是:” << T->rchild->data << endl;
}
else
{
SearchBiTree_H(T->lchild);
SearchBiTree_H(T->rchild);
}
}
return 1;
}
int NodeCount_Tree(BiTree T)
{
if (T == NULL)
{
return 0;
}
else
{
return NodeCount_Tree(T->lchild) + NodeCount_Tree(T->rchild) + 1;
}
}
int NodeCount_Leaf(BiTree T)
{
if (T == NULL)
{
return 0;
}
else
{
if (T->lchild == NULL && T->rchild == NULL)
{
return 1;
}
else
{
return NodeCount_Leaf(T->lchild) + NodeCount_Leaf(T->rchild);
}
}
}
int Tree_Degree(BiTree T)
{
if (T == NULL)
{
return 0;
}
else if ((T->lchild == NULL && T->rchild != NULL) || (T->lchild != NULL && T->rchild == NULL))
{
return 1;
}
else if (T->lchild != NULL && T->rchild != NULL)
{
return 2;
}
}
int Tree_Depth(BiTree T)
{
if (T == NULL)
{
return 0;
}
else
{
int m = Tree_Depth(T->lchild);
int n = Tree_Depth(T->rchild);
if (m > n)
{
return m + 1;
}
else
{
return n + 1;
}
}
}
int main()
{
BiTree T = NULL;
cout << “创建二叉树,请输入一串字符,以^Z结束” << endl;
CreateTree(T);
cout << endl;
cout<<“基于栈的先序遍历:”<<endl;
DLRStack(T);
cout << ‘\n’ << endl;
cout << “H的左右孩子:” << endl;
SearchBiTree_H(T);
cout << endl;
cout << “该二叉树的总结点个数:”;
cout << NodeCount_Tree(T);
cout << ‘\n’ << endl;
cout << “该二叉树的叶子结点的个数:”;
cout << NodeCount_Leaf(T);
cout << ‘\n’ << endl;
cout << “该二叉树的度:”;
cout << Tree_Degree(T);
cout << ‘\n’ << endl;
cout << “该二叉树的深度:”;
cout << Tree_Depth(T);
cout << endl;
}
代码实现部分:

由于树的度是错的,所以重新把创建树的过程重写了一遍
代码重写部分:(我把创建树的方式变了)
void CreateBiTree(BiTree& T)
{
BiTree S[MAXSIZE]; //顺序栈,便于回溯
BiTNode* p = NULL;
int top = 0, k = 0; //top表示一维数组的下标;
T = NULL;
char ch;
cin >> ch;
while (ch != ‘#’)
{
switch (ch)
{
case ‘(’:S[++top] = p; k = 1; break; //top++为入栈,k=1为左子树;
case ‘)’:top–; break; //top–为出栈;
case ‘,’:k = 2; break; //k=2为右子树
default:
p = new BiTNode;
p->data = ch;
p->lchild = p->rchild = NULL;
if (T == NULL) T = p;
else
{
switch (k)
{
case 1:S[top]->lchild = p; break;
case 2:S[top]->rchild = p; break;
}
}
break;
}
cin >> ch;
}
return ;
}
代码重新实现部分:

2.二叉树的各种遍历算法实现
实现上述二叉树的先序、中序和后序遍历的递归和非递归算法;
代码部分:
void DLR_Traversal(BiTree T)
{
if (T == NULL)
{
return;
}
else
{
cout << T->data << " ";
DLR_Traversal(T->lchild);
DLR_Traversal(T->rchild);
}
}
void DLR_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = T;
BiTree q = new BiTNode;
while (p || !StackEmpty(S))
{
if §
{
cout << p->data << " ";
Push(S, p);
p = p->lchild;
}
else
{
Pop(S, q);
p = q->rchild;
}
}
}
void LDR_Traversal(BiTree T)
{
if (T == NULL)
{
return;
}
else
{
LDR_Traversal(T->lchild);
cout << T->data << " ";
LDR_Traversal(T->rchild);
}
}
void LDR_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = T;
BiTree q = new BiTNode;
while (p || !StackEmpty(S))
{
if §
{
Push(S, p);
p = p->lchild;
}
else
{
Pop(S, q);
cout << q->data << " ";
p = q->rchild;
}
}

}
void LRD_Traversal(BiTree T)
{
if (T == NULL)
{
return;
}
else
{
LRD_Traversal(T->lchild);
LRD_Traversal(T->rchild);
cout << T->data << " ";
}
}
void LRD_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = T;
BiTree pre = NULL;
Push(S, p);
while (!StackEmpty(S))
{
Pop(S, p);
if (pre == p->lchild || pre == p->rchild)
{
cout << p->data;
pre = p;
}
else if (p->lchild || p->rchild)
{
Push(S, p);
if (p->rchild)
{
Push(S, p->rchild);
}
if (p->lchild)
{
Pop(S, p->lchild);
}
}
else
{
cout << p->data;
pre = p;
}
}
}
int main()
{
BiTree T = NULL;
cout << “创建二叉树,请输入一串字符,以^Z结束” << endl;
CreateTree(T);
cout << “二叉树的先序递归算法:” << endl;
DLR_Traversal(T);
cout << endl;
cout << “二叉树的中序递归算法:” << endl;
LDR_Traversal(T);
cout << endl;
cout << "二叉树的后序递归算法: " << endl;
LRD_Traversal(T);
cout << endl;
cout << endl;
cout << “二叉树的先序非递归算法:” << endl;
DLR_NOT_Traversal(T);
cout << endl;
cout << “二叉树的中序非递归算法:” << endl;
LDR_NOT_Traversal(T);
cout << endl;
cout << “二叉树的后序非递归算法:” << endl;
LRD_NOT_Traversal(T);
}
代码实现部分:

一看便知,后序的非递归算法有问题:
于是便改成了:
void LRD_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = T;
BiTree pre = NULL;
Push(S, p);
while (!StackEmpty(S))
{
Pop(S, p);
if (pre == p->lchild || pre == p->rchild)
{
cout << p->data;
pre = p;
}
else if (p->lchild || p->rchild)
{
Push(S, p);
if (p->rchild)
{
Push(S, p->rchild);
}
if (p->lchild)
{
Pop(S, p->lchild);
}
}
else
{
cout << p->data;
pre = p;
}
}
}
试过好几次,可还是无法全部输出,到目前为止,此问题仍未解决。

3.线索二叉树的遍历
中序线索化上述二叉树并找出根结点的前驱和后继。
代码部分:
#include
using namespace std;
#define MAXSIZE 100
typedef struct BiThrNode
{
char data;
struct BiThrNode* lchild, * rchild;
int LTag, RTag;
}BiThrNode,BiThrTree;
void Create_ClueTree(BiThrTree& b, char a[])
{
BiThrNode
r[MAXSIZE];
BiThrNode* p = NULL;
int top = -1;
int k, j = 0;
char ch;
b = NULL;
ch = a[j];
while (ch != ‘\0’)
{
switch (ch)
{
case’(’:
top++;
r[top] = p;
k = 1;
break;
case’)’:
top–;
break;
case’,’:
k = 2;
break;
default:
p = new BiThrNode;
p->data = ch;
p->lchild = p->rchild = NULL;
if (b == NULL)
{
b = p;
}
else
{
switch (k)
{
case 1:
r[top]->lchild = p;
break;
case 2:
r[top]->rchild = p;
break;
}
}
}
j++;
ch = a[j];
}
}
BiThrNode* pre;//pre为全局变量,初始化时其右孩子指针为空,便于在树的最左点开始建线索
void InThreading(BiThrTree &p)
{
if §
{
InThreading(p->lchild);//左子树递归线索化
if (!p->lchild)//p的左孩子为空
{
p->LTag = 1;//给p加上左线索
p->lchild = pre;//p的左孩子指针指向pre
}
if (pre != NULL && pre->rchild == NULL)
{
pre->RTag = 1;//给p加上右线索
pre->rchild = p;//pre的右孩子指针指向p的右继
}
pre = p;//保持pre指向p的前驱
InThreading(p->rchild);//右子树递归线索化
}
}
BiThrNode* Pre(BiThrNode* p)
{
if (p->LTag == 1)
{
return p->lchild;
}
BiThrNode* q = p->lchild;
if (q == NULL)
{
cout << “无前驱结点” << endl;
return NULL;
}
while (q->RTag == 0)
{
q = q->lchild;
}
q = q->rchild;
return q;
}
BiThrNode* Next(BiThrNode* p)
{
if (p->RTag == 1)
{
return p->rchild;
}
BiThrNode* q = p->rchild;
if (q == NULL)
{
cout << “无后继结点” << endl;
return NULL;
}
while (q->LTag != 1)
{
q = q->lchild;
}
return q;
}
int main()
{
char a[] = “A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”;
for (int i = 0; i < 37; i++)
{
cout << a[i];
}
cout << endl;
BiThrTree T;
Create_ClueTree(T, a);
InThreading(T);
BiThrTree p, q;
p = Pre(T);
cout << “根节点A前驱:” << p->data << endl;
q = Next(T);
cout << “根节点A后继:” << q->data << endl;
}
代码实现部分:

4.构造哈夫曼树和哈夫曼编码的算法实现
统计下面一段英文的不同字符个数和每个字符的出现频率,利用统计数据构造构造哈夫曼树和哈夫曼编码
The Chinese official said he viewed the Trump Presidency not as an aberration but as the product of a failing political system. This jibes with other accounts. The Chinese leadership believes that the United States, and Western democracies in general, haven’t risen to the challenge of a globalized economy, which necessitates big changes in production patterns, as well as major upgrades in education and public infrastructure. In Trump and Trumpism, the Chinese see an inevitable backlash to this failure.
代码部分:
#include
#include
using namespace std;
#define MAXSIZE 100
typedef struct
{
int weight;
int parent, lchild, rchild;
char ch;
}HTNode,*HuffmanTree;
struct C
{
char ch = 0;
int weight = 0;
};
void Init_HuffmanTree(HuffmanTree& h)//初始化哈夫曼树
{
h = new HTNode;
h->ch = ‘#’;
h->lchild = h->rchild = h->parent = h->weight = 0;
}
void Select(HuffmanTree h, int i, int& s1, int& s2)//选择两个双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
{
s1 = 1;
for (int k = 2; k <= i; k++)
{
if (h[s1].weight > h[k].weight)
{
s1 = k;
}
else if (h[s1].weight <= h[k].weight)
{
s1 = s1;
}
}
if (s1 == 1)
{
s2 = 2;
}
else
{
s2 = 1;
}
for (int k = 2; k <= i; k++)
{
if (k == s1)
{
break;
}
else
{
if (h[s2].weight > h[k].weight)
{
s2 = k;
}
else if (h[s2].weight <= h[k].weight)
{
s2 = s2;
}
}
}
}
void CalculateWeight(string str, HuffmanTree& h)
{
int k = 1;
int flag;
C c[MAXSIZE];
for (int i = 0; i < str.length(); i++)
{
if (str[i] != ’ ')
{
for (int j = 0; j <= k; j++)
{
if (str[i] == c[j].ch)
{
flag = 0;
c[j].weight = c[j].weight + 1;
break;
}
else
{
flag = 1;
}
}
if (flag == 1)
{
c[k].ch = str[i];
k = k + 1;
}
}
}
cout << "Total is " << k - 3 << " different char ";
cout << endl;
for (int j = 32; j <= k - 1; j++)
{
c[j] = c[j + 2];
}
k = k - 3;
int n = 2 * k;
h = new HTNode[n];
HTNode a;
for (int i = 1; i <= n; i++)
{
h[i].ch = ‘#’;
h[i].lchild = h[i].parent = h[i].rchild = h[i].weight = 0;
}
for (int i = 1; i <= k; i++)
{
h[i].ch = c[i].ch;
h[i].weight = c[i].weight + 1;
}
int s1, s2;
for (int i = k + 1; i <= n; i++)
{
Select(h, i - 1, s1, s2);
h[s1].parent = h[s2].parent = i;
h[i].lchild = s1;
h[i].rchild = s2;
h[i].weight = h[s1].weight + h[s2].weight;
}
for (int i = 1; i <= n; i++)
{
cout << h[i].ch << " " << h[i].weight << endl;
}
}
int main()
{
HuffmanTree h;
Init_HuffmanTree(h);
string str = " The Chinese official said he viewed the Trump Presidency not as an aberration but as the product of a failing political system. This jibes with other accounts. The Chinese leadership believes that the United States, and Western democracies in general, haven’t risen to the challenge of a globalized economy, which necessitates big changes in production patterns, as well as major upgrades in education and public infrastructure. In Trump and Trumpism, the Chinese see an inevitable backlash to this failure. " ;
CalculateWeight(str, h);
}
代码实现部分:

<代码/程序执行结果/操作结果>
五、实验结果及分析
<逐条列出代码编写过程中出现的错误,及改正的方案>
问题1:
用先序遍历建立二叉树时,与栈的类型不相容。

解决方案:

将TElemType 类型改为 BiTree后,

仍需把顺序栈的结构改为:

问题二:
创建树时,忘记初始化两个树的指针

问题三:
在基于栈的遍历时,刚开始出现了这个问题,无法输出#号后面的内容。试了几次没成功。检查到入栈和出栈函数时,发现并没有返回值(1或0)。因为先序遍历时,通过flag的值来判断压入栈(flag1)还是弹出栈(flag0),若无返回值,则无法遍历#号后面的内容。

问题四:
在求树的度时,输出值有误
int DegreeBiTree(BiTree T)
{
if (T == NULL)
{
return 0;
}
else if ((T->lchild != NULL && T->rchild == NULL) || (T->lchild == NULL && T->rchild != NULL))
{
return 1;
}
else if (T->lchild != NULL && T->rchild != NULL)
{
return 2;
}
}

原本应该是2的;发现原因是这算法只能算出单个结点的度,并不能求出整个二叉树的度,后来改成了递归形式
int fun(BiTree T,int i)
{
if (T)
{
if ((i < 2) && (T->lchild != NULL) || (T->rchild != NULL))
{
i = 1;
}
if ((T->lchild != NULL) && (T->rchild != NULL))
{
i = 2;
}
fun(T->lchild, i);
fun(T->rchild, i);
}
return i;
}
在main函数中初始化i=0即可,但发现还是错的。

上周四老师给了我这个算法
int fun(BiTree T)
{
if (T == NULL || (T->lchild == NULL) || (T->rchild == NULL))
{
return 0;
}
else
{
int L = fun(T->lchild);
int R = fun(T->rchild);
if (T->lchild != NULL && T->rchild != NULL)
{
return max(2,L,R);
}
if (T->lchild != NULL || T->rchild != NULL)
{
return max(1,L,R);
}
}
}
我把它改成了int fun(BiTree T,int i)这种形式,但树的度还是输不出来。
最后我把创建树的过程改变了
void CreateBiTree(BiTree& T)
{
BiTree S[MAXSIZE]; //顺序栈,便于回溯
BiTNode* p = NULL;
int top = 0, k = 0; //top表示一维数组的下标;
T = NULL;
char ch;
cin >> ch;
while (ch != ‘#’)
{
switch (ch)
{
case ‘(’:S[++top] = p; k = 1; break; //top++为入栈,k=1为左子树;
case ‘)’:top–; break; //top–为出栈;
case ‘,’:k = 2; break; //k=2为右子树
default:
p = new BiTNode;
p->data = ch;
p->lchild = p->rchild = NULL;
if (T == NULL) T = p;
else
{
switch (k)
{
case 1:S[top]->lchild = p; break;
case 2:S[top]->rchild = p; break;
}
}
break;
}
cin >> ch;
}
return ;
}

就能输出度是二的点了。
问题五:
在求二叉树的后序遍历时,出现了以下问题:
本来还有最后一行的,不过程序跑了很久最后才跳出执行完毕,可见应该进入了死循环。

函数体如下:
void LRD_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = NULL;
int a = StackEmpty(S);
while (T || a == 0)
{
while (T)
{
Push(S, T);
T = T->lchild;
}
T = *S.top;
if (T->rchild == NULL || p == T->rchild)
{
cout << T->data;
p = T;
Pop(S, T);
T = NULL;
}
else
{
T = T->rchild;
}
}
}
后来改成了:
void LRD_NOT_Traversal(BiTree T)
{
SqStack S;
InitStack(S);
BiTree p = T;
BiTree pre = NULL;
Push(S, p);
while (!StackEmpty(S))
{
Pop(S, p);
if (pre == p->lchild || pre == p->rchild)
{
cout << p->data;
pre = p;
}
else if (p->lchild || p->rchild)
{
Push(S, p);
if (p->rchild)
{
Push(S, p->rchild);
}
if (p->lchild)
{
Pop(S, p->lchild);
}
}
else
{
cout << p->data;
pre = p;
}
}
}
却只有A能输出;
到目前为止,此问题暂时未解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值