• DS博客作业05-树


    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大佬的脑回路给惊到了,听说这只是签到题,对于我来说,看起来简单,写起来难,看来还是和大佬有着巨大的差距。
  • 相关阅读:
    jquery动画效果---animate()--滚屏
    一个前端的自我修养
    开发和测试
    jquery.find()
    c99和c++11的差异之一
    容器经典图
    C/C++中的##用法
    【心学.悟道】千圣皆过影,良知乃吾师
    memcpy, memset代码改写的方式
    三大软件原则
  • 原文地址:https://www.cnblogs.com/ls1272397716/p/10886851.html
Copyright © 2020-2023  润新知