zoukankan      html  css  js  c++  java
  • 二叉搜索树

    二叉搜索树的建立是通过递归方式来建立的,和普通的二叉树的区别是加上了约束, 它的左子树的所有元素都要比根节点要小, 而右子树的所有元素都要根节点要大,左右子树也符合这个条件。他的遍历方式和普通二叉树的遍历没有什么区别。

    下面是关于二叉搜索树的添加节点和前序遍历,中序遍历, 后续遍历和层级遍历

     1 //递归创建添加新节点
     2 void insertNode(PNode *root, ItemType data)
     3 {
     4     if(*root == NULL)
     5     {
     6         *root = (PNode)malloc(sizeof(Node));
     7         (*root)->data = data;
     8         (*root)->lchild = (*root)->rchild = NULL;
     9     }
    10     else
    11     {
    12         if(data < (*root)->data)
    13             insertNode(&(*root)->lchild, data);
    14         else
    15             insertNode(&(*root)->rchild, data);
    16     }
    17 }
    18 //递归前序遍历
    19 void preOrder(PNode root)
    20 {
    21     if(root == NULL)
    22         return;
    23     printf("%d ", root->data);
    24     preOrder(root->lchild);
    25     preOrder(root->rchild);
    26 }
    27 //递归中序遍历
    28 void inOrder(PNode root)
    29 {
    30     if(root == NULL)
    31         return;
    32     inOrder(root->lchild);
    33     printf("%d ", root->data);
    34     inOrder(root->rchild);
    35 }
    36 //递归后续遍历
    37 void postOrder(PNode root)
    38 {
    39     if(root == NULL)
    40         return;
    41     postOrder(root->lchild);
    42     postOrder(root->rchild);
    43     printf("%d ", root->data);
    44 }
    45 
    46 
    47 //层级遍历
    48 void levelOrder(PNode root)
    49 {
    50     queue<PNode> q;
    51     PNode p = root;
    52     if(p != NULL)
    53         q.push(p);
    54     while(!q.empty())
    55     {
    56         p = q.front();
    57         printf("%d ", p->data);
    58         if(p->lchild != NULL)
    59             q.push(p->lchild);
    60         if(p->rchild != NULL)
    61             q.push(p->rchild);
    62         q.pop();
    63     }
    64 }

    以上这些操作除了插入有点特殊之外和普通的二叉树没有什么区别,下面主要来说二叉树的非递归遍历方法, 其中包括前序,中序和后续。其中前序和中序差不多,比较好理解点。

    前序主要就是打印出节点的值, 再将左子树入栈,出栈时再栈顶的遍历右子树。下面是代码的实现

     1 void preOrder_NonRecursion(PNode root)
     2 {
     3     stack<PNode> s;
     4     PNode p = root;
     5     while(p != NULL || !s.empty())
     6     {
     7         if(p != NULL)//如果存在,继续找他的左孩子
     8         {
     9             printf("%d ", p->data);
    10             s.push(p);
    11             p = p->lchild;
    12         }
    13         else//没有的话,将p指向栈顶的元素,出栈操作,继续找右孩子
    14         {
    15             p = s.top();
    16             s.pop();
    17             p = p->rchild;
    18         }
    19     }
    20 }

    非递归的中序遍历和前序差不多,就改变输出的值,因为前序遍历是先根再左再右, 而中序是左根右, 所以只是输出顺序不同了而已

     1 //非递归中序遍历
     2 void inOrder_NonRecursion(PNode root)
     3 {
     4     stack<PNode> s;
     5     PNode p = root;
     6     while(p != NULL || !s.empty())
     7     {
     8         if(p != NULL)//左孩子不为空就进栈,继续它的左孩子
     9         {
    10             s.push(p);
    11             p = p->lchild;
    12         }
    13         else//输出栈顶的元素,然后出栈,找它右兄弟(程序中是先找父亲,然后找父亲的右孩子)
    14         {
    15             p = s.top();
    16             printf("%d ", p->data);
    17             s.pop();
    18             p = p->rchild;
    19         }
    20     }
    21 }

    非递归的后续遍历稍微比前序和中序复杂了一点,但也不是很复杂,因为后续遍历是先左后右再根的, 所以根是最后的,所以加了一个布尔变量来标记他的右子树遍历了没有,其它的和前序和中序没什么大的区别, bool变量为true的时候说明他的右子树还没有遍历。false是已经遍历过了

     1 void postOrder_NonRecursion(PNode root)
     2 {
     3     stack<pair<PNode, bool> > s;//用pair使s 的类型为PNode和bool的复合类型
     4     PNode p = root;
     5     while(p != NULL || !s.empty())
     6     {
     7         if(p != NULL)//如果当前节点不为空的话,入栈, 继续找它的左孩子
     8         {
     9             s.push(make_pair(p, false));//初始的时候没有遍历他的右子树
    10             p = p->lchild;
    11         }
    12         else//否则去栈顶
    13         {
    14             if(s.top().second == false)//如果它的右子树没有没遍历
    15             {
    16                 s.top().second = true;//标记已经遍历过
    17                 p = s.top().first->rchild;//遍历右子树
    18             }
    19             else//遍历过了,直接输出, 因为此时节点为当前树的根节点
    20             {
    21                 printf("%d ", s.top().first->data);
    22                 s.pop();
    23             }
    24         }
    25     }
    26 }

    还有就是求树的高度, 一般是用递归来实现, 递归比价好理解, 代码也比较简洁, 但是有时候也需要非递归方式来求,下面是递归方式求的, 比较简单

     1 //递归求树的深度
     2 int getDepth(PNode root)
     3 {
     4     int d1, d2;
     5     if(root == NULL)
     6         return 0;
     7     d1 = getDepth(root->lchild);
     8     d2 = getDepth(root->rchild);
     9     return (d1 > d2 ? d1 : d2) + 1;
    10 }

    非递归的方式求书的高度的思想是:一层一层的遍历, 当遍历一层的时候, 层数加一, 但是怎么确定这层是否遍历完呢, 这时就需要三个变量来合作记录了,一个last_level_number来记录以上层一共有多少个入队的, in_queue_number 来记录所有入队的了有几个, 还有一个是visit_number来记录当前已经出队了几个元素了, 也就是有多少个节点已经扩展了子节点, 也就是广搜的那个扩展, 主要还是利用层级遍历的思想, 需要一个队列

     1 //非递归求数的深度
     2 int getDepth_NonRecursion(PNode root)
     3 {
     4     if(root == NULL)
     5         return 0;
     6     queue<PNode> q;
     7     PNode p = root;
     8     q.push(p);
     9     int last_level_number = 1;//用来标记一共有多少个曾经入过队
    10     int visit_number = 0;//记录已经扩展了的节点
    11     int in_queue_number = 1;//所有入队的有所少个
    12     int height = 0;
    13     while (!q.empty())
    14     {
    15         visit_number++;//出队一次加一个, 也就是扩展一次, 加一次
    16         p = q.front();
    17         q.pop();
    18         //分别扩展它的左孩子和右孩子
    19         if (p->lchild != NULL)
    20         {
    21             q.push(p->lchild);
    22             in_queue_number++;
    23         }
    24         if(p->rchild != NULL)
    25         {
    26             q.push(p->rchild);
    27             in_queue_number++;
    28         }
    29         //如果到一层的结尾
    30         if(visit_number == last_level_number)
    31         {
    32             height++;
    33             last_level_number = in_queue_number;//更新last_level_number
    34         }
    35     }
    36     return height;
    37 }

    还有就是求二叉搜索树中任意给定两个节点的最近的共同祖先, 这里是二叉搜索树比较简单, 如果不是二叉搜索树就比较麻烦了,暂时只说二叉搜索树的, 非二叉搜索树的后面补上。

    主要思想是:利用二叉搜索树的性质, 任意的左孩子都比根节点小, 任意的右节点都比根节点大, 所以,直接拿着两个点和根节点进行比价, 如果都比根节点大的话, 就说明共同祖先肯定在根节点的右边, 如果都小的话, 就说明都在根节点的左边, 如果一小一大那就好办了, 直接就是根节点了, 继续找左子树或者右子树。下面是代码的实现'

    //求两节点的最近的共同祖先
    void getCommonAncestor(PNode root, ItemType n1, ItemType n2)
    {
        if(root == NULL)
            return;
        while((n1 < root->data && n2 < root->data) || (n1 > root->data && n2 > root->data) )
        {
            if(n1 < root->data)
                root = root->lchild;
            else
                root = root->rchild;
        }
        printf("latest common ancestor: %d
    ", root->data);
    }

    求二叉树的镜像,二叉树的镜像的意思就是将他的各个左右节点都反过来, 听着很麻烦, 其实递归很简单的, 只需要先把他的左右子树交换过来, 然后再继续递归他的左右子树就行了

    代码如下:

     1 //求二叉树的镜像
     2 void mirror(PNode root)
     3 {
     4     if(root != NULL)
     5     {
     6         //交换它的左右子树
     7         PNode p = root->lchild;
     8         root->lchild = root->rchild;
     9         root->rchild = p;
    10         //递归它的左右子树
    11         mirror(root->lchild);
    12         mirror(root->rchild);
    13     }
    14 }

    下面是所有的实现的完整代码

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <math.h>
      4 #include <stack>
      5 #include <queue>
      6 
      7 using namespace std;
      8 
      9 typedef int ItemType;
     10 typedef struct Node{
     11     ItemType data;
     12     struct Node *lchild, *rchild;
     13 }Node, *PNode;
     14 //递归创建添加新节点
     15 void insertNode(PNode *root, ItemType data)
     16 {
     17     if(*root == NULL)
     18     {
     19         *root = (PNode)malloc(sizeof(Node));
     20         (*root)->data = data;
     21         (*root)->lchild = (*root)->rchild = NULL;
     22     }
     23     else
     24     {
     25         if(data < (*root)->data)
     26             insertNode(&(*root)->lchild, data);
     27         else
     28             insertNode(&(*root)->rchild, data);
     29     }
     30 }
     31 //递归前序遍历
     32 void preOrder(PNode root)
     33 {
     34     if(root == NULL)
     35         return;
     36     printf("%d ", root->data);
     37     preOrder(root->lchild);
     38     preOrder(root->rchild);
     39 }
     40 //递归中序遍历
     41 void inOrder(PNode root)
     42 {
     43     if(root == NULL)
     44         return;
     45     inOrder(root->lchild);
     46     printf("%d ", root->data);
     47     inOrder(root->rchild);
     48 }
     49 //递归后续遍历
     50 void postOrder(PNode root)
     51 {
     52     if(root == NULL)
     53         return;
     54     postOrder(root->lchild);
     55     postOrder(root->rchild);
     56     printf("%d ", root->data);
     57 }
     58 //非递归前序遍历
     59 void preOrder_NonRecursion(PNode root)
     60 {
     61     stack<PNode> s;
     62     PNode p = root;
     63     while(p != NULL || !s.empty())
     64     {
     65         if(p != NULL)//如果存在,继续找他的左孩子
     66         {
     67             printf("%d ", p->data);
     68             s.push(p);
     69             p = p->lchild;
     70         }
     71         else//没有的话,将p指向栈顶的元素,出栈操作,继续找右孩子
     72         {
     73             p = s.top();
     74             s.pop();
     75             p = p->rchild;
     76         }
     77     }
     78 }
     79 //非递归中序遍历
     80 void inOrder_NonRecursion(PNode root)
     81 {
     82     stack<PNode> s;
     83     PNode p = root;
     84     while(p != NULL || !s.empty())
     85     {
     86         if(p != NULL)//左孩子不为空就进栈,继续它的左孩子
     87         {
     88             s.push(p);
     89             p = p->lchild;
     90         }
     91         else//输出栈顶的元素,然后出栈,找它右兄弟(程序中是先找父亲,然后找父亲的右孩子)
     92         {
     93             p = s.top();
     94             printf("%d ", p->data);
     95             s.pop();
     96             p = p->rchild;
     97         }
     98     }
     99 }
    100 //非递归后续遍历
    101 void postOrder_NonRecursion(PNode root)
    102 {
    103     stack<pair<PNode, bool> > s;//用pair使s 的类型为PNode和bool的复合类型
    104     PNode p = root;
    105     while(p != NULL || !s.empty())
    106     {
    107         if(p != NULL)//如果当前节点不为空的话,入栈, 继续找它的左孩子
    108         {
    109             s.push(make_pair(p, false));//初始的时候没有遍历他的右子树
    110             p = p->lchild;
    111         }
    112         else//否则去栈顶
    113         {
    114             if(s.top().second == false)//如果它的右子树没有没遍历
    115             {
    116                 s.top().second = true;//标记已经遍历过
    117                 p = s.top().first->rchild;//遍历右子树
    118             }
    119             else//遍历过了,直接输出, 因为此时节点为当前树的根节点
    120             {
    121                 printf("%d ", s.top().first->data);
    122                 s.pop();
    123             }
    124         }
    125     }
    126 }
    127 //层级遍历
    128 void levelOrder(PNode root)
    129 {
    130     queue<PNode> q;
    131     PNode p = root;
    132     if(p != NULL)
    133         q.push(p);
    134     while(!q.empty())
    135     {
    136         p = q.front();
    137         printf("%d ", p->data);
    138         if(p->lchild != NULL)
    139             q.push(p->lchild);
    140         if(p->rchild != NULL)
    141             q.push(p->rchild);
    142         q.pop();
    143     }
    144 }
    145 //求一层的所有节点
    146 void specifyLevelNode(PNode root, int h)//h是指定的高度
    147 {
    148     if(root == NULL)
    149         return;
    150     queue<PNode> q;
    151     PNode p = root;
    152     q.push(p);
    153     int last_level_number = 1;//用来标记以上所有层多少个
    154     int visit_number = 0;
    155     int in_queue_number = 1;//入队的多少个
    156     int height = 0;
    157     while (!q.empty())
    158     {
    159         visit_number++;
    160         p = q.front();
    161         q.pop();
    162 
    163         if (p->lchild != NULL)
    164         {
    165             q.push(p->lchild);
    166             in_queue_number++;
    167             if (h - 2 == height)/*因为这个高度执行到后面才++, 所以h要减一,
    168             还有就是当前是p->lchild而不是p,所以在减一*/
    169                 printf("%d ", p->lchild->data);
    170         }
    171         if(p->rchild != NULL)
    172         {
    173             q.push(p->rchild);
    174             in_queue_number++;
    175             if (h - 2== height)//同上
    176                 printf("%d ", p->rchild->data);
    177         }
    178 
    179         if(visit_number == last_level_number)
    180         {
    181             height++;
    182             last_level_number = in_queue_number;
    183         }
    184     }
    185 }
    186 //递归求树的深度
    187 int getDepth(PNode root)
    188 {
    189     int d1, d2;
    190     if(root == NULL)
    191         return 0;
    192     d1 = getDepth(root->lchild);
    193     d2 = getDepth(root->rchild);
    194     return (d1 > d2 ? d1 : d2) + 1;
    195 }
    196 //非递归求数的深度
    197 int getDepth_NonRecursion(PNode root)
    198 {
    199     if(root == NULL)
    200         return 0;
    201     queue<PNode> q;
    202     PNode p = root;
    203     q.push(p);
    204     int last_level_number = 1;//用来标记一共有多少个曾经入过队
    205     int visit_number = 0;//记录已经扩展了的节点
    206     int in_queue_number = 1;//所有入队的有所少个
    207     int height = 0;
    208     while (!q.empty())
    209     {
    210         visit_number++;//出队一次加一个, 也就是扩展一次, 加一次
    211         p = q.front();
    212         q.pop();
    213         //分别扩展它的左孩子和右孩子
    214         if (p->lchild != NULL)
    215         {
    216             q.push(p->lchild);
    217             in_queue_number++;
    218         }
    219         if(p->rchild != NULL)
    220         {
    221             q.push(p->rchild);
    222             in_queue_number++;
    223         }
    224         //如果到一层的结尾
    225         if(visit_number == last_level_number)
    226         {
    227             height++;
    228             last_level_number = in_queue_number;//更新last_level_number
    229         }
    230     }
    231     return height;
    232 }
    233 //求二叉树中相距最远的两个节点之间的距离
    234 int getMaxDistance(PNode root)
    235 {
    236     if(root == NULL)
    237         return 0;
    238     return getDepth(root->lchild) + getDepth(root->rchild);
    239 }
    240 //求两节点的最近的共同祖先
    241 void getCommonAncestor(PNode root, ItemType n1, ItemType n2)
    242 {
    243     if(root == NULL)
    244         return;
    245     while((n1 < root->data && n2 < root->data) || (n1 > root->data && n2 > root->data) )
    246     {
    247         if(n1 < root->data)
    248             root = root->lchild;
    249         else
    250             root = root->rchild;
    251     }
    252     printf("latest common ancestor: %d
    ", root->data);
    253 }
    254 
    255 //求路径和为指定值的所有路径
    256 
    257 int main()
    258 {
    259 
    260     PNode root = NULL;
    261     int test[8] = {8, 5, 16, 1, 4, 9, 24, 7};
    262     for(int i = 0; i < 8; i++)
    263     {
    264         insertNode(&root, test[i]);
    265     }
    266     printf("Previous Order Traverse:
    ");
    267     preOrder(root);
    268     printf("
    In Order Traverse:
    ");
    269     inOrder(root);
    270     printf("
    Post Order Traverse:
    ");
    271     postOrder(root);
    272     printf("
    Non-Recursion Previous Order Traverse:
    ");
    273     preOrder_NonRecursion(root);
    274     printf("
    Non-Recursion In Order Traverse:
    ");
    275     inOrder_NonRecursion(root);
    276     printf("
    Non-Recursion Post Order Traverse:
    ");
    277     postOrder_NonRecursion(root);
    278     printf("
    Level Order Traverse:
    ");
    279     levelOrder(root);
    280     printf("
    The depth of tree: %d
    ", getDepth(root));
    281     printf("The depth of tree(Non-Recursion): %d
    ", getDepth_NonRecursion(root));
    282     specifyLevelNode(root, 3);//求第三层的所有节点
    283     printf("
    The max distance: %d
    ", getMaxDistance(root));
    284     getCommonAncestor(root, 7, 4);//测试数据,得出7和4的最近祖先
    285 
    286     return 0;
    287 }
  • 相关阅读:
    【jekins】jenkins构建触发
    【Autoit】Autoit 使用
    docker 网络和/etc/docker/daemon.json文件详情
    kubernetes(k8s)集群安全机制RBAC
    linux文件目录颜色及特殊权限对应的颜色
    Python 爬取各大代理IP网站(元类封装)
    K8S 容器之间通讯方式
    kubernetes Pod的升级与回滚
    lvs+keepalived+mariadb集群
    kubernetes(k8s)Pod污点与容忍
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4035650.html
Copyright © 2011-2022 走看看