1.本周学习总结
1.1.思维导图
1.2.谈谈你对树结构的认识及学习体会。
对于树结构的认识,它既可以顺序结构存储,也可以用链式结构存储,在刚刚预习树结构中的链式存储时,我感觉它的操作跟链表一样,结构体中的指针移来移去,没想到使用递归,看起来方便许多,但是,由于上学期没好好学递归,只是粗略的看了一遍,到了树这里开始还债了,在学习树的过程中又要把递归好好理解一边,勉强读懂了一些关于树的操作的代码,但是如果要求写,可能有些费劲, 但是再敲pta的表达式树时,发现树的结点还能用栈和队列存储,在我以前敲的pta题目中,只有数字和字符使用过栈和队列,没想到自己建的结构体也能用栈和队列来操作,知识果然是一直叠加的。课本在介绍树形结构时,写了许多关于树的专属名词,什么孩子结点、双亲结点、兄弟结点等等,概念非常多,都需要我们理解。二叉树是特殊的一种树,而哈夫曼树又是一种特殊的二叉树,对于哈夫曼树,一位哈夫曼树只有下图这一种,根节点的一个结点为叶子结点,没想到做课堂派题目还有多种的哈夫曼树结构,不局限于下图那种。上周末参加了acm志愿者活动,跟一个参赛的学长交流时,他谈到树的这一章挺重要的,他们考的一题中有需要建立哈夫曼树,可以看出数据结构有多重要。
2.PTA实验作业
2.1.题目1:6-4 jmu-ds-表达式树
2.1.1设计思路
void InitExpTree(BTree &T, string str)
建立字符栈opchar
建立树结点栈node
创建树结点p等于NULL,a,b
while str[i]!=' '
if str[i]是数字0到9 then
将结点存入树栈node中
else if str[i]是运算符 then
if opchar栈为空 then
将字符存入opchar栈中
else
f = Precede(op.top(), str[i]) //栈顶元素与字符的优先级
switch f
case:'>': //优先级比栈顶元素低
取node栈顶两个元素并赋值给a,b
利用CreateExpTree建树
opchar出栈
再将新建的树入栈
case '<':
字符入栈 //优先级比栈顶元素高
case '=':
opchar栈出栈 //优先级与栈顶元素相同
end while
while opchar不空且node栈也不空
取node栈顶两个元素并赋值给a,b
利用CreateExpTree建树
opchar出栈
再将新建的树入栈
end while
double EvaluateExTree(BTree T)
定义浮点数sum,b,m
建立浮点型栈num
建立字符栈s
建立树类型的栈node
while T!=NULL
将每个结点存入s,以及将结点T存入node中
end while
while s!=NULL
if str[i]是数字0到9 then
将字符转化浮点型数并存入num中
else
取栈顶的两个元素赋值给sum,b
出栈
switch s的栈顶元素
case '+':sum += b;
case '-':sum -= b;
case '*':sum *= b;
case '/':
if b==0 then
输出divide 0 error!
退出程序
else sum /= b;
end if
s栈出栈
将sum入到num栈
返回sum
2.1.2代码截图
2.1.3本题PTA提交列表说明。
1.在用vs运行程序时,老是会跳出下图的问题,然后将代码提交到pta上,发现是段错误,然后问了大佬,可能出现了野指针或者是没有出栈,后面发现自己忘记出栈了,导致程序一直循环
2.在计算表达式时,忘记设置返回值了。
3.由于EvaluateExTree返回值为浮点型,但是当除数等于0时,必须返回一个值,刚开始不知道怎么做,后面舍友告诉我可以用exit(0)直接退出程序。
2.2 题目2:7-2 根据后序和中序遍历输出先序遍历
2.2.1设计思路
int main()
定义 n, i
定义一个树节点T;
输入 n
for i=0 to n do
输入后序排列的元素
end for
for i=0 to n do
输入中序排列的元素
end for
利用Build函数建树
输出"Preorder:"
利用PreOrder函数输出前序序列
return 0
BiTree Build(int *in, int *post, int n)
定义整型变量len, 整型指针*p
if n <= 0 then
return NULL
end if
for p=in to in+n
if *p == *(post + n - 1) then
break;
end if
enf for
建立新结点T
T->data = *p
len = p - in;
T->lchild = Build(in, post, len);
T->rchild = Build(p + 1, post + len, n - len - 1);
返回T
void PreOrder(BiTree T)
if T!=NULL then
输出 T->data;
PreOrder(T->lchild); // 利用递归前序排列
PreOrder(T->rchild);
end if
2.2.2代码截图
2.2.3本题PTA提交列表说明。
1.在头两次次的提交中,弄错了循环条件,程序一直退不出来。
2.刚开始还不知道怎么写,后来看了书,勉强理解了,然后自己敲,错误百出。然后再次百度代码,发现自己没有把递归口弄好。才导致了这么多次的答案错误。
2.3 题目3:7-4 jmu-ds-二叉树叶子结点带权路径长度和
2.3.1设计思路
int main()
定义str数组
输入str
定义wpl为带权路径长度
利用creat函数建树
利用GetWPL函数计算带权路径长度和
BiTree create(string str, int n)
建立新的树节点 BT
if 字符为# then
返回NULL
end if
if n的值大于数组长度 then
返回NULL
end if
BT->data = str[n];
BT->lchild = create(str, 2 * n); //使用递归建树
BT->rchild = create(str, 2 * n+1);
返回 BT;
void GetWPL(BiTree bt,int h,int&wpl)
if bt==NULL then
结束函数
end if
if bt左右孩子都不空 then
wpl=wpl+(bt->data-'0')*h;
end if
GetWPL(bt->lchild,h+1,wpl); //使用递归计算带权路径长度和
GetWPL(bt->rchild,h+1,wpl);
2.3.2代码截图
2.3.3本题PTA提交列表说明。
1.多次发生段错误是因为忘记设置递归口了,程序跳不出来。
2.在建树和计算表达式利用自己定义的变量会发生错误,所以直接用数字传参。
3.再写建树的函数时,只考虑到str[i]=‘#’这种情况,没有想到如果传进去的n如果大于字符串的长度会怎么样。
3、阅读代码
3.1 题目
3.2 解题思路
根据前序、中序序列还原建树,然后镜面反转,就是将非叶子节点的左右孩子互换,最后层序遍历输出这棵树。
3.3 代码截图
#include<iostream>
#include<queue>
#define maxn 1000
using namespace std;
int n;
int qian[1000],zh[1000];
struct node
{
int l,r;
}pp[1000];
int build(int la,int ra,int lb,int rb)
{
if(la>ra)
return 0;
int root,p1,p2;
root=qian[lb];
p1=la;
while(zh[p1]!=root)
p1++;
p2=p1-la;
pp[root].l=build(la,p1-1,lb+1,lb+p2-1);
pp[root].r=build(p1+1,ra,lb+p2+1,rb);
return root;
}
void fan(int root)
{
if(pp[root].l || pp[root].r)
{
int temp = pp[root].l;
pp[root].l = pp[root].r;
pp[root].r = temp;
if(pp[root].l)
fan(pp[root].l);
if(pp[root].r)
fan(pp[root].r);
}
}
void level()
{
queue<int>q;
q.push(qian[0]);
cout<<qian[0];
while(!q.empty())
{
int temp = q.front();
q.pop();
if(temp!=qian[0])
cout<<' '<<temp;
if(pp[temp].l)
q.push(pp[temp].l);
if(pp[temp].r)
q.push(pp[temp].r);
}
cout<<endl;
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i++)
cin>>zh[i];
for(int i = 0; i < n; i++)
cin>>qian[i];
build(0,n-1,0,n-1);
fan(qian[0]);
level();
return 0;
}
3.4 学习体会
初看这道题·,思路并不难,我以为直接按书本上的代码建树,然后在交换非叶子节点的左右孩子就行了,但是看到大佬写的代码,真的给跪了,他的结构体中只有整型的r与l代表着左右孩子,方便了下面编写交换非叶子结点的左右孩子,如果要是我来写的话,我肯定又要建栈,入栈,出栈,这样即增加了程序的空间复杂度,写出来的代码又难懂,而大佬直接用上学期交换数字来写,简单易懂,下面的输出则是用队列来写,而最主要的建树函数,他把里面的递归条件拿捏的特别好,和树上用链式存储结构差不多,用数组来存储二叉树看起来要比链式存储更容易理解,真的为那些acm大佬的脑回路给惊到了,听说这只是签到题,对于我来说,看起来简单,写起来难,看来还是和大佬有着巨大的差距。