zoukankan      html  css  js  c++  java
  • 第八篇博客

    这个作业属于哪个班级 数据结构--网络2011/2012
    这个作业的地址 DS博客作业03--树
    这个作业的目标 学习树结构设计及运算操作
    姓名 卢伟杰

    0.PTA得分截图

    1.本周学习总结(5分)

    1.1 二叉树结构

    • 二叉树的2种存储结构

      • 二叉树的存储结构有两种:顺序存储结构和链式存储结构
    • 顺序存储结构

      顺序结构实现二叉树时,采用一个一维数组来存储所有结点,需要将所有结点按照在树中的位置安排成一个恰当的序列,使其能反应结点之间相互的逻辑关系,通常使用编号的方法;
      

    • 链式存储结构

      由二叉树的定义可知,二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支构成,则表示二叉树的链表中的结点至少包含3个域:数据域和左、右指针域;

    • 树的顺序存储和链式存储结构,并分析优缺点

      • 顺序存储

        优点:读取某个指定的节点的时候效率比较高O(0)

        缺点:会浪费空间(在非完全二叉树的时候)

      • 链式存储

        优点:读取某个指定节点的时候效率偏低O(nlogn)

        缺点:相对二叉树比较大的时候浪费空间较少

        二叉树的顺序存储,寻找后代节点和祖先节点都非常方便,但对于普通的二叉树,顺序存储浪费大量的存储空间,同样也不利于节点的插入和删除。因此顺序存储一般
        用于存储完全二叉树。链式存储相对顺序存储节省存储空间,插入删除节点时只需修改指针,但寻找指定节点时很不方便。不过普通的二叉树一般是用链式存储结构。

    • 二叉树的构造

    • 创建二叉树

     void CreateBTree(BTNode *&b, char *str)    
     {
         BTNode *p, *St[MaxSize];    
         int k, j = 0, top = -1;    
         char ch;
         b = NULL;   
         ch = str[j];
         while (ch != '')    
         {
             switch (ch)
             {
             case'(':top++; St[top] = p; k = 1; break;   
             case ',':k = 2; break;    
             case ')':top--; break;    
             default:
                 p = (BTNode *)malloc(sizeof(BTNode));   
                 p->data = ch;    
                 p->lchild = p->rchild = NULL;    
                 if (b == NULL)    
                 {
                     b = p;   
                 }
                 else    
                 {
                     switch (k)
                     {
                     case 1:St[top] = p->lchild; break;    
                     case 2:St[top] = p->rchild; break;    
                     }
                 }
             }
             j++;
             ch=str[j];    
         }
     }
    
    • 销毁二叉树
    void DestroyBTree(string str, int &i)
    {
          if (b != NULL)
          {
              DestroyBTree(b->lchild);
              DestroyBTree(b->rchild);
              free(b);
          }
    }
    
    
    • 查找节点
    BTNode * FindNode(BTNode *b, Elemtype x)
    { 
    	BTNode* p;
    	if (b == NULL)
            {
                return NULL;
            }
            else if(b->data == x)
                return b;
            else
            {
                p = FindNode(b->lchild, x);
                if(p != NULL)
                    return p;
            else
                return FindNode(b->rchild, x);
            }
    }
    
    • 找孩子节点
    void FindChild(BiTree T)
    {
    	if(T->lChild == NULL && T->rChild == NULL)
    	{
    		cout << T->data << " ";
    		return ;
    	}
    	FindChild(T->lChild);
    	FindCHild(T->rChild);
    }
    
    
    • 求高度
    int BTHeight(BTNode *b)
    {
            int lchild,rchild;
            if(b == NULL)
              return(0);
            else
            {
                lchild = BTHeight(b->lchild);
                rchild = BTHeight(b->rchild);
                return (lchild>rchild)?(lchild+1):(rchild+1);
            }
    }
    
    • 二叉树的遍历

    • 先序遍历

      先序遍历的递归过程为:若二叉树为空,遍历结束。否则:

      a.访问根结点;
      b.先序遍历根结点的左子树;
      c.先序遍历根结点的右子树。 简单来说先序遍历就是在深入时遇到结点就访问。
      

      先序遍历的递归算法:

    void PreOrder(BTree bt)
    {     
            if (bt!=NULL)  
            {     
                   printf("%c ",bt->data); 	
                   PreOrder(bt->lchild);
                   PreOrder(bt->rchild);
            }
    }
    
    • 中序遍历

      中序遍历的递归过程为:若二叉树为空,遍历结束。否则:

      a.中序遍历根结点的左子树;
      b.访问根结点;
      c.中序遍历根结点的右子树。
      
      简单来说中序遍历就是从左子树返回时遇到结点就访问。
      

      中序遍历的递归算法:

    void InOrder(BTree bt)
    {       
           if (bt!=NULL) 
           {
                 InOrder(bt->lchild);
                 printf("%c ",bt->data); 	
                 InOrder(bt->rchild);
           }
    }
    
    • 后序遍历

      后序遍历的递归过程为:若二叉树为空,遍历结束。否则:

      a.后序遍历根结点的左子树;
      b.后序遍历根结点的右子树;
      c.访问根结点。
      
      简单来说后序遍历就是从右子树返回时遇到结点就访问。
      

      后序遍历的递归算法:

    void PostOrder(BTree bt) 
    {      
           if (bt!=NULL)  
           {      
                 PostOrder(bt->lchild);
    	     PostOrder(bt->rchild);
    	     printf("%c ",bt->data); 	
           }
    }
    
    • 层次遍历

      这棵二叉树的层次遍历次序为:A、B、C、D、F、G 每次出队一个元素,就将该元素的孩子节点加入队列中,
      直至队列中元素个数为0时,出队的顺序就是该二叉树的层次遍历结果.

      层次遍历的递归算法

    void Create_Level(Node* &t){
    	queue<Node*> q;
    	int x;
    	cin>>x;
    	if (x!=0) {
    		Create_Node(t,x);
    		q.push(t);
    	}
    	while (!q.empty()){
    		Node* s=q.front();
    		cin>>x;
    		if (x!=0){
    			Create_Node(s->leftchild,x);
    			q.push(s->leftchild);
    		}
    		cin>>x;
    		if (x!=0){
    			Create_Node(s->rightchild,x);
    			q.push(s->rightchild);
    		}
    		q.pop();
    	}
    }
    
    
    • 线索二叉树

    二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,
    最后一个结点无后继)。对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。为了容易找到
    前驱和后继,有两种方法。一是在结点结构中增加向前和向后的指针,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。

    • 结构体定义
    typedef struct node 
      {      ElemType data;		
             int ltag,rtag;      		
             struct node *lchild;		
             struct node *rchild;		
      }  TBTNode;		 
    
    • 优势

        利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间。
        任意一个结点都能直接找到它的前驱和后继结点。
      
    • 劣势
      结点的插入和删除麻烦,且速度也较慢。
      线索子树不能共用。

    void InThreading(BiThrTree*p);
    BiThrNodeType*pre;
    BiThrTree*InOrderThr(BiThrTree*T)
    {
          BiThrTree*head;
          head=(BitThrNodeType*)malloc(sizeof(BitThrNodeType));
          head->ltag=0;head->rtag=1;
          head->rchild=head;
          if(!T)
          head->lchild=head;
          else
          {
              head->lchild=T;pre=head;
              InThreading(T);
              pre->rchild=head;
              pre->rtag=1;
              head->rchild=pre;
          }
          returnhead;
    }
    voidInThreading(BiThrTree*p)
    {
          if(p)
          {
          InThreading(p->lchild);
          if(p->lchild==NULL)
          {
             p->ltag=1;
              p->lchild=pre;
          }
          else
              p->ltag=0;
          if(p->rchild==NULL)
              p->rtag=1;
          else
              p->rtag=0;
          if(pre!=NULL&&pre->rtag==1)
              pre->rchild=p;
              pre=p;
              InThreading(p->rchild);
          }
    }
    
    • 二叉树的应用--表达式树

     先序遍历表达式树,得到的是前缀表达式
    
     中序遍历表达式树,得到的是中缀表达式
    
     后序遍历表达式树,得到的是后缀表达式
    

    • 构建表达式树

      可以从后缀表达式来构建一个表达式树,如果是中缀表达式,则可以先转化为后缀表达式;

    createExpressionTree(suffixExpression)
        stack s  <- empty stack;
        for each element E in suffixExpression do
            if(E is 操作数 )
                Node tree = new Node(E)
                s.push(tree)
            else if(E is 运算符)
                Node secondOperand = s.pop()
                Node firstOperand  =s.pop() 
                Node tree = new Node(E)
                tree.setLeft(firstOperand)
                tree.setRight(secondOperand)
                s.push(tree);
            
        return s.pop()      
    

    1.2 多叉树结构

    • 多叉树结构:树的每个节点可以有两个以上的子节点,称为m阶的多叉树,或者称为m叉树。

    • 多叉树遍历

    • 递归

    public static void Recursion(TreeNode root) 
    {
        System.out.print(root.getName());
        for (TreeNode treeNode : root.getChildren()) 
        {
            Recursion(treeNode);
        }
    }
    
    • 广度优先
    public static void breadthFirst(TreeNode root) 
    {
        Deque<TreeNode> nodeDeque = new LinkedList<>();
        TreeNode node = root;
        nodeDeque.push(node);
        while (!nodeDeque.isEmpty()) 
        {
            node = nodeDeque.pop();
            System.out.print(node.getName());
            for (TreeNode treeNode : node.getChildren()) 
            {
                nodeDeque.addLast(treeNode);
            }
        }
    }
    
    • 深度优先
    public static void depthFirst(TreeNode root) 
    {
        Deque<TreeNode> nodeDeque = new LinkedList<>();
        TreeNode node = root;
        nodeDeque.push(node);
        while (!nodeDeque.isEmpty()) 
        {
            node = nodeDeque.pop();
            System.out.print(node.getName());
            for (TreeNode treeNode : node.getChildren()) 
            {
                nodeDeque.push(treeNode);
            }
        }
    }
    

    1.3 哈夫曼树

    • 哈夫曼树定义:给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,
      也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

    • 哈夫曼树的结构体

    typedef struct
    {
          char data;
          double weight;
          int parent;
          int lchild;
          int rchild;
    }HTNode;
    
    • 哈夫曼树构建及哈夫曼编码
    typedef struct {
        int weight;        
        int parent, lc, rc; 
    } HTNode, *HuffmanTree;
     
    void Select(HuffmanTree &HT, int n, int &s1, int &s2)
    {
        int minum;   
        for(int i=1; i<=n; i++)   
        {
            if(HT[i].parent == 0)
            {
                minum = i;
                break;
            }
        }
        for(int i=1; i<=n; i++)
        {
            if(HT[i].parent == 0)
                if(HT[i].weight < HT[minum].weight)
                    minum = i;
        }
        s1 = minum;
        for(int i=1; i<=n; i++)     
        {
            if(HT[i].parent == 0 && i != s1)
            {
                minum = i;
                break;
            }
        }
        for(int i=1; i<=n; i++)
        {
            if(HT[i].parent == 0 && i != s1)
                if(HT[i].weight < HT[minum].weight)
                    minum = i;
        }
        s2 = minum;
    }
     
    void CreatHuff(HuffmanTree &HT, int *w, int n)
    {
        int m, s1, s2;
        m = n * 2 - 1; 
        HT = new HTNode[m + 1]; 
        for(int i=1; i<=n; i++)
        {
            HT[i].weight = w[i];
            HT[i].parent = 0;
            HT[i].lc = 0;
            HT[i].rc = 0;
        }
        for(int i=n+1; i<=m; i++)   
        {
            HT[i].weight = 0;
            HT[i].parent = 0;
            HT[i].lc = 0;
            HT[i].rc = 0;
        }
        
        printf("
    the HuffmanTree is: 
    ");
     
        for(int i = n+1; i<=m; i++)     
        {   
            Select(HT, i-1, s1, s2);
            HT[s1].parent = i;  
            HT[s2].parent = i;
            HT[i].lc = s1;    
            HT[i].rc = s2;
            HT[i].weight = HT[s1].weight + HT[s2].weight;   
            printf("%d (%d, %d)
    ", HT[i].weight, HT[s1].weight, HT[s2].weight);
        }
        printf("
    ");
    }
     
    int main()
    {
        HuffmanTree HT;
        
        int *w, n, wei;
        printf("input the number of node
    ");
        scanf("%d", &n);
        w = new int[n+1];
        printf("
    input the %dth node of value
    ", n);
     
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &wei);
            w[i] = wei;
        }
        CreatHuff(HT, w, n);
     
     
     
        return 0;
    }
    

    1.4 并查集

    • 并查集:是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示。

    • 并查集解决什么问题,优势在哪里?
      并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图
      的连通分量个数、最小公共祖先、带限制的作业排序,还有最完美的应用:实现Kruskar算法求最小生成树。

    • 并查集的结构体、查找、合并操作如何实现?

    template<typename T> class Node{
    public:
        T value;
        Node<T>* father;
        int size;
        Node(T value, T* father){
            this->value = value;
            this->father = father;
            this->length = 0;
        }
        Node(T value){
            this->value = value;
            this->father = NULL;
            this->length = 0;
        }
        Node(){
            this->value = 0;
            this->father = 0;
            this->size = 0;
        }
    };
    
    

    2.PTA实验作业(4分)

    2.1 二叉树

    • 输出二叉树每层节点
    #include<iostream>
    #include<string>
    #include<queue>
    using namespace std;
    typedef char ElemType;
    typedef struct BiTNode
    {
        ElemType data;
        struct BiTNode *lchild,*rchild;
    }*BTree,BiTree;
    BTree CreatTree(string str ,int &i);
    void PreOrder(BTree b,int h);
    void LevelOrder(BTree bt);
    int wpl = 0;
    int main()
    {
        string str;
        cin>>str;
        int MaxSize;
        int i=0;
        BTree bt =CreatTree(str,i);
        LevelOrder(bt);
        return 0;
    }
    BTree CreatTree(string str,int &i)
    {
        BTree bt;
        if(i > str.size()-1)
        {
            return NULL;
        }
        if(str[i]=='#')
        {
            return NULL;
        }
        bt = new BiTree;
        bt->data=str[i];
        bt->lchild=CreatTree(str,++i);
        bt->rchild=CreatTree(str,++i);
        return bt;
    }
    void PreOrder(BTree b,int h)
    {
        if(b!=NULL)
        {
            cout<<b->data<<",";
        PreOrder(b->lchild,h+1);
        PreOrder(b->rchild,h+1);
        }
    }
    void LevelOrder(BTree bt)
    {
        BTree p,ptr;
        ptr = new BiTree;
        ptr->lchild = NULL;
        ptr->rchild = NULL;
        ptr->data='0';
        p=new BiTree;
        p->lchild = NULL;
        p->rchild = NULL;
        p->data = '0';
        queue<BTree>q;
        if(bt != NULL)
        {
            q.push(bt);
            cout<<"1:"<<bt->data<<",";
            ptr=bt;
        }
        else
        {
            cout<<"NULL";
            return;
        }
        int i=2;
        int flag=0;
        while (!q.empty())
        {
            p=q.front();
            q.pop();
            if (flag==1)
            {
                cout<<p->data<<",";
            }
            flag=1;
            if(p->lchild!=NULL)
            {
                q.push(p->lchild);
            }
            if(p->rchild!=NULL)
            {
                q.push(p->rchild);
            }
            if (p == ptr)
            {
                if(!q.empty())
                {
                    cout << endl << i << ":";
                    ptr = q.back();
                }
                i++;
            }
        }
    }
    
    • 解题思路及伪代码
    BinTree CreatBT(string str,int &i)
    {
            当i>len-1或str[i]='#'
             返回NULL
            定义树的结构变量BT
            申请结点BTNode
            将str[i]的值赋给BT->data
            递归调用函数CreatTree构建左右孩子
            返回bt
     }
    void Print(BinTree BT) 
    {
           定义树的结构变量curNode,lastNode
           flag==1,表示该层输出完成,level表示该结点第几层
           把树赋给curNode,lastNode,然后让树中的结点进栈 
           遍历栈,对头赋给curNode,判断为左孩子还是右孩子或者与lastNode相等,进行相应的赋值 
           用flag控制树层
           最后输出栈顶
    }
    

    3.阅读代码(0--1分)

    3.1 题目及解题代码

    • 翻转二叉树以匹配前序遍历

    3.2 该题的设计思路及伪代码

    • 解题思路:

    该题也是递归思想的应用。按照题目要求进行前序遍历,一旦遇到对应值与目标数组结果不同时,翻转遍历,
    接着继续遍历,如果最终结果依然不匹配则返回false,否则返回true。可截图,或复制代码,需要用代码符号渲染。

    • 代码
    class Solution {
        private int index;
        private int[] voyage;
        private List<Integer> result;
        
        public List<Integer> flipMatchVoyage(TreeNode root, int[] voyage) {
            // index = 0;
            this.voyage = voyage;
            result = new ArrayList<>();
            dfs(root);
            // System.out.println("result = "+result);
            if(result.size() > 0 && result.get(result.size()-1) == -1)
                return new ArrayList<Integer>(Arrays.asList(-1));
            return result;
        }
        
        public void dfs(TreeNode root) {
            if(root == null)
                return;
            if(root.val != voyage[index++]) 
                result.add(-1);
            else {
                if(root.left != null && root.left.val != voyage[index]) {
                    result.add(root.val);
                    dfs(root.right);
                    dfs(root.left);
                } else {
                    dfs(root.left);
                    dfs(root.right);
                }
            }
        }
    }
    
    
  • 相关阅读:
    刷题-力扣-152. 乘积最大子数组
    刷题-力扣-剑指 Offer II 088. 爬楼梯的最少成本
    刷题-力扣-剑指 Offer II 003. 前 n 个数字二进制中 1 的个数
    刷题-力扣-LCS 01. 下载插件
    刷题-力扣-剑指 Offer 10- II. 青蛙跳台阶问题
    20191107-3 beta week 2/2 Scrum立会报告+燃尽图 02
    beta week 2/2 Scrum立会报告+燃尽图 01
    版本控制报告
    20191031-9 beta week 1/2 Scrum立会报告+燃尽图 07
    扛把子组20191031-2 Beta阶段贡献分配规则
  • 原文地址:https://www.cnblogs.com/eau2077/p/14726418.html
Copyright © 2011-2022 走看看