• DS博客作业03-树


    0.PTA得分截图

    1.本周学习总结

    1.1 总结树及串内容

    串的概念:由有限个字符组成的序列
    字串:串中任意个连续的字符组成的子序列
    主串:包含字串的串
    
    BF算法(又称古典的、穷举的)
    特点:目标串上的指针需要不停地回溯,效率较差
    
    KMP算法
    特点:指针不需要回溯,匹配速度快
    含义:定义一个next[j]数组,当主串字符op与子串失配时,op下回应和子串第next[j]个字符比较
    改进KMP算法:由于next数组有缺陷例如主串为aaabaaaaaaaaaaaaaab,子串为aaaab,由于next[j]=k,而
    子串中t[j]=t[k],所以当失配时,主串不用与t[k]进行比较,因而引入nextval[j]数组
    


    二叉树的性质
    1.非空二叉树上叶子节点树等于双分支节点数加1,即n0=n2+1
    2.在二叉树的第i层上至多有2^(i-1)个节点(i>=1)
    3.高度为h的二叉树至多有2^h-1个节点
    二叉树存储结构
    typedef struct Tnode
    {
        char/int data;
        struct Tnode* lchild,rchild;
    }BiTnode,*BTree;
    二叉树的创建方法:
    1.将二叉树的顺序存储结构转为二叉链                             2.前序序列创建二叉树
    BTree createTree(string s,int i)                            BTree createTree(string s,int& i)
    {                                                           {
        if(i>=s.size或s[i]=='#')return NULL;                        if(i>=s.size)return NULL;     
        创建根节点B,B->data=s[i];                                   if(s[i]为#)i++,return NULL;
        创建左子树:B->lchild=createTree(s,2*i);                      创建根节点B,B->data=s[i];i++;      
        创建右子树:B->rchild=createTree(s,2*i+1);                    创建左子树:B->lchild=createTree(s,i);
        return B;                                                   创建右子树:B->rchild=createTree(s,i); 
    }                                                               retirn B;
                                                                }
    3.表达式建树
    void InitExpTree(BTree& T, string str)
    {
            初始化数根栈tree,运算符栈s;
            定义BTree T1,T2;
            while(str[i]!='')
            {
                若str[i]为数字,则新建一棵以str[i]为数根的树,然后进数根栈;
                若为运算符
    	       栈顶运算符优先级小于str[i]或栈空,则将str[i]进运算符栈s
    	       大于则从tree栈中弹出两棵树和从s中弹出一个运算符树生成一棵新树并进树栈
    	       若等于则删除运算符栈的栈顶元素s.pop()
            }	        
           将运算符剩余元素弹出建树
    }
    4.括号法建树,前序和中序建树,中序和后序建树等
    
    根据前序序列和中序序列建树
    Tree create(char* pre, char* in, int n)
    {
    	Tree s;
    	char* p;
    	int k;
    
    	if (n <= 0)
    		return NULL;
    	s = new BiTnode;
    	s->data = *pre;
    	for (p = in; p < in + n; p++)
    	{
    		if (*p == *pre)
    			break;
    	}
    	k = p - in;
    	s->lchild = create(pre + 1, in, k);
    	s->rchild = create(pre + k + 1, p + 1, n - k - 1);
    	return s;
    }
    
    根据后序序列和中序序列建树
    Tree create(int* post, int* in, int n)
    {
    	Tree s;
    	int* p;
    	int k;
        
        if(n<=0)
        {
            return NULL;
        }
    	s = new BiTnode;
    	s->data = *(post + n - 1);
    
    	for (p = in; p < in + n; p++)
    	{
    		if (*p == *(post + n - 1))
    			break;
    	}
    	k = p - in;
    	s->lchild = create(post, in, k);
    	s->rchild = create(post + k, p + 1, n - k - 1);
    	return s;
    }
    二叉树的遍历
    void PreOrder(BTree T)//先序遍历    void InOrder(BTree T)//中序遍历      void PostyOrder(BTree T)//后序遍历
    {                                  {                                    {
        if(T!=NULL)                          if(T!=NULL)                          if(T!=NULL)
        {                                    {                                    {
            cout<<T->data;                      InOrder(T->lchild);                   PostOrder(T->lchild); 
            PreOrder(T->lchild);                cout<<T->data;                        PostOrder(T->rchild);
            PreOrder(T->rchild);                InOrder(T->rchild);                   cout<<T->data;
        }                                    }                                    }
    }                                   }                                   }
    二叉树的应用:
    1.文档中的很多属性和项目靠树来爬取分析
    2.求二叉树的高度,找某个值等
    int GetHeight(BinTree BT)//求二叉树高度
    {
        int high1 = 0;
        int high2 = 0;
        if (BT == NULL)
            return 0;
        high1 = GetHeight(BT->Left)+1;
        high2 = GetHeight(BT->Right)+1;
        if (high1 > high2)//比较左右树高度的大小
            return high1;
        else
            return high2;
    }
    3.将中缀表达式放入二叉树中,后序遍历二叉树可得后缀表达式
    void InitExpTree(BTree& T, string str)
    {
        int i = 0;
        stack<BTree> tree;//存放树根的栈
        stack<char> s;//存放运算符的栈
        BTree T1, T2;
        char ch;
    
        while (str[i] != '')
        {
            if (!In(str[i]))//是数字直接进树栈
            {
                T = new BTNode;
                T->data = str[i];
                T->lchild = NULL;
                T->rchild = NULL;
                tree.push(T);
                i++;
            }
            else//是运算符
            {
                if (s.empty() || Precede(s.top(), str[i]) == '<')//栈空或者栈顶运算符优先级小于str[i]
                {
                    s.push(str[i]);
                    i++;
                }
                else if (Precede(s.top(), str[i]) == '>')//栈顶运算符优先级大于str[i]
                {
                    ch = s.top();//出栈一个运算符
                    s.pop();
    
                    T2 = tree.top();//出栈两棵树
                    tree.pop();
    
                    T1 = tree.top();
                    tree.pop();
    
                    CreateExpTree(T, T1, T2, ch);//生成一棵新树
                    tree.push(T);//将新生成的树入树栈
    
                }
                else//栈顶运算符优先级大于str[i]
                {
                    s.pop();//出栈运算符栈
                    i++;
                }
            }
        }
        while (!s.empty())//若运算符栈不空,则出栈生成树
        {
            ch = s.top();
            s.pop();
    
            T2 = tree.top();
            tree.pop();
    
            T1 = tree.top();
            tree.pop();
    
            CreateExpTree(T, T1, T2, ch);
            tree.push(T);
    
        }
    }
    double EvaluateExTree(BTree T)
    {
        double  a, b;
    
        if (!T->lchild && !T->rchild)//叶子节点均为操作数
        {
            return T->data - '0';
        }
        a = EvaluateExTree(T->lchild);
        b = EvaluateExTree(T->rchild);
        switch (T->data)
        {
        case '+':return a + b;
        case '-':return a - b;
        case '*':return a * b;
        case '/':
            if (b == 0)
            {
                cout << "divide 0 error!";
                exit(0);//除0错误,结束程序
            }
            return a / b;
        }
    }
    
    树的一些术语和性质
    1.根:即根节点,没有前驱
    2.叶子:即终端节点,没有子树
    3.森林:指m棵不相交的树的集合
    4.有序树:节点从左到右有序,不能互换
    5.无序树:节点各子树可互换位置
    6.双亲:即上层的那个节点(直接前驱)
    7.孩子:即下层节点的子树的根(直接后继)
    8.兄弟:同一双亲下的同层节点
    9.祖先:即从根到该节点所经分支的所有节点
    10.子孙:即该节点下层子树中的任一节点
    11.节点:即树的数据元素
    12.度:节点的子树目,分支数目
    13.节点的层次:从根到该节点的层数,根节点算一层
    14.终端节点:即叶子
    15.分支节点:即度不为的节点,也称为内部节点
    16.树的深度:指所有节点中最大的层数
    性质一:树中的节点树等于所有节点的度数之和加1
    性质二:度为m的树的第i层上至多有m^(i-1)个节点(i>=1)
    
    树的存储结构
    双亲存储结构                  孩子存储结构                         孩子兄弟链存储结构
    typedef struct               typedef struct node                 typedef struct Tnode
    {                            {                                   {        
        int data;                     int data;                            int data;
        int parent;                    struct node*sons[MAXSons];          struct tnode*son;
    }PTree[MAXSIZE];             }SonNode;                                 struct tnode*brother;
    缺点:找孩子不容易              缺点:找父亲不容易                    }TSBnode;
                                                                     缺点:找父亲不容易
    遍历方法:
    先根遍历:若树不空,先遍历根节点,然后依次先根遍历各棵子树
    后根遍历:若树不空,则先依次后根遍历各棵子树,然后访问根节点
    层次遍历:若树不空,自上而下,从左到右访问每个节点
    树的应用:
    1.目录树
    2.二叉树转为树,树转为二叉树
    3.查询重复率
    
    线索二叉树
    概念:二叉链存储结构时,每个节点有两个指针域,利用空链域,指向线性序列中的前驱和后继
    存储结构
    typedef struct Tnode
    {
        char/int data;
        int ltag,rtag;
        struct Tnode* lchild,rchild;
    }BiTnode,*BTree;
    当ltag=0时,lchild指向其左孩子
    当ltag=1时,lchild指向其前驱
    当rtag=0时,rchild指向其右孩子
    当rtag=1时,rchild指向其前驱
    

    哈夫曼树:具有最小带权路径长度的树称为哈夫曼树
    创建过程:在给定的n个权值(F=(T1,T2....Tn))中选取权值最小的两个权值作为左右孩子,
    根节点为两个孩子的权值之和,再将新树放入F中,反复进行以上操作,最后当F中只剩一棵树时,
    该树为哈夫曼树。
    

    创建哈夫曼树过程如下


    并查集
    存储结构
    typedef struct node
    {
        int data;
        int rank;
        int parent;
    }UFSTree;
    并查集树初始化                              查找一个元素所属的集合
    void Make_set(UFSTree t[],int n)           int find(UFSTree t[],int x)
    {                                          {
          int i;                                    if(x!=t[x].parent)
          for(i=1;i<=n;i++)                             return find(t,t[x].parent);
          {                                         else
             t[i].data=i;                                return x;//双亲是自己                 
             t[i].rank=0;                       }
             t[i].parent=i;
          }
    }    
    两个元素所属集合的合并
    void Union(UFSTree t[],int x,int y)
    {
          x=find(t,x);
          y=find(t,y);
          if(t[x].rank>t[y].rank)//y的秩小于x的秩
             t[y].parent=x;//将y连到x节点上
          else
          {
             t[x].parent=y;//将x连到y上
             if(t[x].rank==t[y].rank)//相等
                 t[y].rank++;//y节点的秩增1
          } 
    }                                       
    

    1.2.谈谈你对树的认识及学习体会。

    树的内容比较多,有很多新的词语,比如叶子,根,度等,学习起来的时间大都比较长,编程难度也比较大,
    由于树的创建遍历以及应用等大都需要递归,理解起来便更有难度了,不过通过编程之后可以慢慢理解,用心
    学的话也会发现内容比较有趣

    2.阅读代码

    2.1 题目及解题代码

    题目:相同的树

    2.1.1 该题的设计思路

    使用递归的方式同步遍历两棵树,开始先判断有无空树的情况,然后比较节点值的大小,最后再进行遍历即可。

    2.1.2 该题的伪代码

    bool isSameTree(TreeNode* p, TreeNode* q) 
    {
          if树p和q都为空,return true;
          else if树p和q只有一个为空,return false;
          
          if节点值p->val!=q->val,return false;
           
           递归遍历左树和右树
           if(!isSameTree(p->left,q->left)) return false;
           if(!isSameTree(p->right,q->right)) return false;
            return true;
    }
    

    2.1.3 运行结果


    2.1.4分析该题目解题优势及难点。

    解题优势:运用了递归的方法解题,代码简短,可读性好,而且虽然用了递归,但也好理解
    难点:递归窗口的设计,对递归遍历树要比较熟悉

    2.2 题目及解题代码

    题目:对称二叉树

    2.2.1 该题的设计思路

    2.2.2 该题的伪代码

    bool isSymmetric(TreeNode* root) 
    {
            if(为空树) return true;
            否则return isMirror(root->left,root->right);//判断是否镜像对称
    }
     bool isMirror(TreeNode *p,TreeNode *q) 
    {
         if左右子树都为空,return true;
         if左右子树只有一个为空,return false;
         左右子树的值相等,一直递归调用
         return (p->val==q->val) && isMirror(p->left,q->right) && isMirror(p->right,q->left);
    
    }
    

    2.2.3 运行结果


    2.2.4分析该题目解题优势及难点。

    解题优势:return (p->val==q->val) && isMirror(p->left,q->right) && isMirror(p->right,q->left)感觉很厉害,即判断了值相等不
    还厉害了镜像对称的特点,左子树的左子树跟右子树的右子树对应,左子树的右子树跟右子树的左子树对应

    难点:递归函数的设计和镜像对称用代码的表示

    2.3 题目及解题代码

    题目:路径总和

    2.3.1 该题的设计思路

    1、判断边界条件。(1)root为null。(2)root左右子树为null。
    2、深度搜索左右子树。

    2.3.2 该题的伪代码

     bool hasPathSum(TreeNode* root, int sum) 
    {
            return DFS(root, sum);//判断是否存在所给路径和
    }
    bool DFS(TreeNode* root, int sum)
    {
           if(root==NULL)说明前面都不满足路径和的值,return NULL;
           if(左右子树都为空)
               if(root的值为sum)return true;
           递归调用,sum的值每次减小root->val;
           return (DFS(root->left, sum-root->val) || DFS(root->right, sum -root->val);
    }
    
    

    2.3.3 运行结果

    2.3.4分析该题目解题优势及难点。

    解题优势:代码易懂,巧妙设计递归参数的值,每次递归都使sum的值减少,逆向求路径和
    难点:函数参数的值的设计,题目的理解也有一定难度

    2.4 题目及解题代码

    题目:二叉树的最小深度

    2.4.1 该题的设计思路

    思路:遇到叶子节点不递归而是返回值,遇到其他节点则继续递归

    2.4.2 该题的伪代码

    int minDepth(TreeNode* root)
    {
            if(root为空) return NULL;
            int level=1;
            if(root为叶节点)  return level;
            
            若左孩子空,求右子树深度;
            return level+minDepth(root->right);
             若右孩子空,求左子树深度;
            return level+minDepth(root->left);
            最后求都不空的情况
            return level+min(minDepth(root->left),minDepth(root->right));
    }
    

    2.4.3 运行结果

    2.4.4分析该题目解题优势及难点。

    解题优势:函数设计巧妙,且代码简洁,用min来取左右的最小深度
    题目难度:读清题意,是叶子的最小深度,函数的返回值的设计

  • 相关阅读:
    css3实现酷炫的3D盒子翻转效果
    Java源码学习:HashMap实现原理
    mac 如何显示隐藏文件和.点开头文件?
    mac 下 安装 mongodb 数据库
    WPF 自定义TextBox
    Appium+Python 安卓APP自动化测试:安装app和卸载app
    Appium+Python 安卓APP自动化测试:环境搭建与基础操作
    DataFrame利用函数或映射进行数据转换map
    TypeError: drop_duplicates() got an unexpected keyword argument 'take_last'
    DataFrame合并:合并重叠数据combine_first
  • 原文地址:https://www.cnblogs.com/sym2446/p/12660465.html
Copyright © 2020-2023  润新知