• 树-上


    查找

    根据某个给定关键字K,从集合R中找出关键字与K相同的记录

    • 静态查找:集合记录是固定的->没有插入和删除操作,只有查找
    • 动态查找:集合中记录是动态变化的->除查找,还可能发生插入和删除

    静态查找

    • 顺序查找,时间复杂度为O(n)
    int SequentialSearch(StaticTable *Tbl,ElementType K){
          //在表Tbl[1]~Tb1[n]中查找关键字为K的数据元素
          int i;
          Tb1->Element[0]=K;//建立哨兵,让数组下标为0的位置的值为K
          for(i=Tb1->Length;Tb1->Element[i]!=K;i--);
          return i;//查找成功返回所在位置下标,不成功返回0
    
    • 二分查找,时间复杂度为O(logN)

    假设n个数据元素的关键字满足有序并且是连续存放就可以进行二分查找

    int BinarySearch(StaticTable *Tbl,ElementType K){
          //在表Tbl中查找关键字为K的数据元素
          int left,right,mid,NoFound=-1;
          left=1;                          //初始左边界
          right=Tbl->Length;               //初始右边界
          while(left<=right){
                mid=(left+right)/2;        //计算中间元素坐标
                if(K<Tbl->Element[mid])      right=mid-1;//调整右边界
                else if(K>Tbl->Element[mid]) left=mid+1; //调整左边界
                else return mid;             //查找成功,返回数据元素的小标
          }
          return NotFound;                   //查找不成功,返回-1
    }
    

    二分查找判定树

    • 判定树上每个结点需要的查找次数为该结点所在的层数
    • 查找成功时查找次数不会超过判定树的深度
    • n个结点的判断树的深度为[log2(n)]+1
    • 平均查找次数(ASL) 每一层的结点个数乘以层数

    树的定义

    n个结点构成的有限集合 当n=0时称为空树

    • 对于任一棵非空树(n>0) 具备以下性质:
    1. 树中有一个称为“根”的特殊结点,用r表示;
    2. 其余结点可分为m(m>0个互不相交的有限集T1,,Tn,其中每个集合本身又是一棵树,称为原来树的“子树”
    3. 子树互不相交
    4. 除了根结点外,每个结点有且仅有一个父结点
    5. 一棵N个结点的树有N-1条边

    树的基本用语

    • 结点的度(Degree):结点的子树个数
    • 树的度:树的所有结点中最大的度
    • 叶结点(Leaf):度为0的结点
    • 父结点(Parent):有子树的结点是其子树的根结点的父结点
    • 子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点;子结点也称孩子结点
    • 兄弟结点(Sibling):具有同一父结点的各结点彼此是兄弟结点
    • 路径和路径长度:从结点n1到nk的路径为一个结点序列n1,,,,nk,ni是ni+1的父结点。路径所包含边的个数为路径长度
    • 祖先结点(Ancestor):沿树根到某一结点路径上的所有结点都是这个结点的祖先结点
    • 子孙结点:某一结点的子树中的所有结点是这个结点的子孙
    • 结点的层次:规定根结点在1层,其它任一结点的层数是其父结点的层数加1
    • 树的深度(Depth):树中所有结点中的最大层次是这棵树的深度

    二叉树及存储结构

    • 二叉树的定义

    一个有穷的结点的集合 这个集合可以为空;若不为空,则它是由根结点和称为其左子树T[L]和右子树T[R]的两个不相交的二叉树组成

    • 二叉树有左右之分

    特殊的二叉树

    • 斜二叉树
    • 完美二叉树/满二叉树
    • 完全二叉树

    有n个结点的二叉树,对树中结点按从上至下,从左到右的顺序进行编号,编号为i(1<=i<=n)结点与满二叉树中编号为i结点在二叉树中位置相同 完全二叉树是完美二叉树的子集,而且是连续不断的那种

    二叉树的几个重要性质

    • 一个二叉树第i层的最大结点数为:2^(i-1),i>=1;
    • 深度为K的二叉树有最大结点总数为:2^(k)-1,k>=1
    • 对任何非空二叉树T,若n[0]表示叶结点的个数,n[2]是度为2的非叶结点个数,那么两者满足关系n[0]=n[2]+1

    二叉树的抽象数据类型定义

    • 操作集
    1. Boolean IsEmpty(BinTree BT):判别BT是否为空
    2. void Traversal(BinTree BT):遍历,按某顺序访问每个结点
    3. BinTree CreatBinTree():创建一个二叉树
    
    • 常用遍历方法
    1. void PreOrderTraversal(BinTree BT):先序--根,左子树,右子树
    2. void InOrderTraversal(BinTree BT):中序--左子树,根,右子树
    3. void PostOrderTraversal(BinTree BT):后序--左子树,右子树,根
    4. void LevelOrderTraversal(BinTree BT):层次遍历,从上到下,从左到右
    

    二叉树的存储结构

    顺序存储结构

    • 完全二叉树

    按从上至下,从左到右的顺序存储n个结点的完全二叉树的结点父子关系

    • 一般二叉树采用上述结构会造成很大的空间浪费

    链表存储

    typedef struct TreeNode *BinTree;
    typedef BinTree Position;
    struct TreeNode{
          ElementType Data;
          BinTree Left;
          BinTree Right;
    };
    

    二叉树遍历

    先序遍历中序遍历后序遍历其实差距不大 访问根结点的顺序不一样

    • 递归遍历
    //先序遍历
    //1.访问根结点
    //2.先序遍历左子树
    //3.先序遍历右子树
    void PreOrderTraversal(BinTree BT){
          if(BT){
                printf("%d",BT->Data);
                PreOrderTraversal(BT->Left);
                PreOrederTraversal(BT->Right);
          }
    }
    
    //中序遍历
    //1.中序遍历左子树
    //2.访问根结点
    //3.中序遍历右子树
    void InOrderTraversal(BinTree BT){
          if(BT){
                InOrderTraversal(BT->Left);
                printf("%d",BT->Data);
                InOrderTraversal(BT->Right);
    
    //后序遍历
    //1.后序遍历左子树
    //2.后序遍历右子树
    //3.访问结点
    void PostOrderTraversal(BinTree BT){
          if(BT){
                PostOrderTraversal(BT->left);
                PostOrderTraversal(BT->Right);
                printf("%d",BT->Data);
          }
    }
    
    • 先序中序后序遍历过程:遍历过程中经过结点的路线一样,只是访问各结点的时机不同

    非递归遍历算法

    • 中序遍历非递归算法
    • 遇到一个结点,就把它压栈,并去遍历它的左子树
    • 当左子树遍历结束后,从栈顶弹出这个结点并访问它
    • 然后按其右指针再去中序遍历该结点的右子树
    void InOrderTraversal(BinTree BT){
          BinTree T=BT;
          Stack S = CreatStack(MaxSize);
          while(T||!TsEmpty(s)){
                while(T){         //一直向左并将沿途结点压入堆栈
                      Push(S,T);
                      T=T->Left;
                }
                if(!TsEmpty(s)){
                      T=Pop(S);  //结点弹出堆栈
                      printf("%5d",T->Data);  //打印结点
                      T=T->Right;   //转向右子树
                }
          }
    }
    
    • 先序遍历非递归算法
    void InOrderTeaversal(BinTree BT){
          BinTree T BT;
          Stack S=CreatStack(MaxSize);
          while(T||!IsEmpty(S)){
                while(T){
                      Push(S,T);
                      T=T->Left;
                }
                if(!IsEmpty(S)){
                      T=Pop(S);
                      T=T->Right;
                }
          }
    }
    

    层序遍历

    • 队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队,访问该结点,其左右儿子入队
    //从队列中取出一个元素
    //访问该元素所指结点
    //若该元素所指结点的左右孩子结点非空,则将其左右孩子的指针顺序入队
    void LevelOrderTraversak ( BinTree BT ){
          Queue Q;BinTree T;
          if ( !BT ) return;
          Q = CreatQueue ( MaxSize );
          AddQ ( Q,BT );
          while ( !IsEmptyQ ( Q ) ){
                T = DeleteQ( Q );
                printf("%d
    ",T->Data);
                if (T->Left) AddQ(Q,T->Left);
                if (T->Right)AddQ(Q,T->Right);
          }
    }
    
    • 遍历二叉树的应用,输出二叉树中的叶子结点
    void PreOrderPrintLeaves (BinTree BT){
          if(BT){
                if(!BT->Left && !BT->Right){
                      printf("%d",BT->Data);
                PreOrderPrintLeaves (BT->Left);
                PreOrderPrintLeaves (BT->Right);
    
    • 求二叉树的高度
    //Height=max(Hl,Hr)+1
    int PostOrderGetHeight(BinTree BT){
          int HL,HR,MaxH;
          if(BT){
                HL=PostOrderGetHeight(BT->Left);
                HR=PostOrderGetHeight(BT->Right);
                MaxH=(HL>HR)?HL:HR;
                return (MaxH+1);
          }
          else return 0;
    }
    
    • 二元运算表达式树及其遍历
    1. 先序遍历得到前缀表达式
    2. 中序遍历得到中缀表达式(得到的中缀表达式可能会改变原表达式的意思)
    3. 后序遍历得到后缀表达式
    
    • 可有中序遍历和其他两种遍历中的任意一种共同确定一个二叉树
    1. 根据先序遍历序列第一个结点确定根结点
    2. 根据结点在中序遍历序列中分割出左右两个子序列
    3. 对左右子树分别递归使用相同的方法继续分解
    
  • 相关阅读:
    java,jenkins
    docker compose,link,Odoo
    nginx,docker反向代理
    centos7上安装docker-ce社区版
    Install Rancher server
    docker公司测试环境搭建总结
    ansible+docker
    桥接物理网卡,pipwork指定ip,外网连接,研究salt+docker
    20170605
    20170602
  • 原文地址:https://www.cnblogs.com/Alex3O/p/13365086.html
Copyright © 2020-2023  润新知