• 数据结构——二叉树


    一、二叉树的递归定义    

    1.  要么二叉树没有根节点,是一棵空树。
    2.  要么二叉树由根节点、左子树、右子树组成,且左子树和右子树都是二叉树。   

     

    二、二叉树的存储结构

      一般来说,二叉树使用链表来定义。二叉树每个结点有两条出边,因此指针域有两个——分别指向左子树和右子树的根结点地址,因此右把这种链表叫做二叉链表。其定义方式如下:

    1 #define typename int
    2 // 二叉树结构定义 
    3 struct node {
    4     typename data;        // 数据域
    5     node* lchild;        // 指向左子树的根结点
    6     node* rchild;        // 指向右子树的根结点 
    7 };

      如果需要新建结点,可以使用下面的函数:

    1 // 生成一个新节点,v为数据 
    2 node* newNode(typename v) {
    3     node* Node = (node*)malloc(sizeof(node));
    4     Node->data = v;
    5     // 初始状态下没有左右子树 
    6     Node->lchild = Node->rchild = NULL;
    7     return Node;
    8 } 

    三、二叉树的基本操作

      二叉树的常用操作有以下几个:二叉树的建立、二叉树结点的查找、修改、插入与删除。本节主要介绍查找、修改、插入、建树的通用思想。

      1. 二叉树结点的查找、修改

      查找操作是指在给定数据域的条件下,在二叉树中找到所有数据域为给定数据域的结点,并将它们的数据域修改为给定的数据域。  

      可以使用递归来完成查找修改操作。先判断当前结点是否是需要查找的结点:如果是,则对其进行修改操作;如果不是,则分别往该结点的左孩子和右孩子递归,直到当前结点为 NULL 为止。代码如下:

     1 // 在根结点为root的二叉树查找所有数据域为x的结点并修改为newdata 
     2 void search(node* root, typename x, typename newdata) {
     3     if(root == NULL) {
     4         return;        // 空树 
     5     }
     6     if(root->data == x) {    // 查到 x 
     7         root->data = newdata;    // 修改 
     8     }
     9     search(root->lchild, x, newdata);    // 遍历左子树
    10     search(root->rchild, x, newdata);    // 遍历右子树      
    11 } 

      2. 二叉树结点的插入

      二叉树结点的插入位置与二叉树本身的性质有关,下面代码以二叉排序树为例:

     1 // 在以*root为根结点的二叉树插入一个新节点 
     2 void insert(node** root, typename x) {
     3     if((*root) == NULL) {        // 找到插入位置 
     4         (*root) = newNode(x);
     5         return; 
     6     }
     7     if(x < (*root)->data) {        // 往左子树插入 
     8         insert(&((*root)->lchild), x);
     9     } else {                    // 往右子树插入 
    10         insert(&((*root)->rchild), x);
    11     }
    12 }

      在上述代码中,函数参数使用了二维指针 **。这么做的原因是,在 insert 函数中新建了结点,并把新结点的地址赋给了当层的 root。

      那么,如何判断是否要加指针呢?一般来说,如果函数中需要新建结点,即对二叉树的结构做出修改,就需要加引用;如果只是修改当前已有结点的内容,或仅仅是遍历树,就不用加指针。

      3. 二叉树的创建

      二叉树的创建其实就是二叉树结点的插入过程,比较常用的写法是把需要插入的数据存储在数组中,然后再将它们使用 insert 函数一个个插入二叉树中,并最终返回根结点的指针 root。代码如下:

    // 二叉树的建立 
    node* create(typename data[], int n) {
        node* root = NULL;        // 新建空根结点 root 
        int i;
        for(i=0; i<n; ++i) {    // 将 data 中的数据插入二叉树 
            insert(&root, data[i]);
        } 
        return root;            // 返回根结点 
    } 

      完整 C 代码如下:

     1 /*
     2     二叉树 
     3 */
     4 
     5 #include <stdio.h>
     6 #include <string.h>
     7 #include <math.h>
     8 #include <stdlib.h>
     9 #include <time.h>
    10 #include <stdbool.h>
    11 
    12 #define typename int
    13 // 二叉树结构定义 
    14 typedef struct _node {
    15     typename data;        // 数据域
    16     struct _node* lchild;        // 指向左子树的根结点
    17     struct _node* rchild;        // 指向右子树的根结点 
    18 } node; 
    19 
    20 // 生成一个新节点,v为数据 
    21 node* newNode(typename v) {
    22     node* Node = (node*)malloc(sizeof(node));
    23     Node->data = v;
    24     // 初始状态下没有左右子树 
    25     Node->lchild = Node->rchild = NULL;
    26     return Node;
    27 } 
    28 
    29 // 在根结点为root的二叉树查找所有数据域为x的结点并修改为newdata 
    30 void search(node* root, typename x, typename newdata) {
    31     if(root == NULL) {
    32         return;        // 空树 
    33     }
    34     if(root->data == x) {    // 查到 x 
    35         root->data = newdata;    // 修改 
    36     }
    37     search(root->lchild, x, newdata);    // 遍历左子树
    38     search(root->rchild, x, newdata);    // 遍历右子树      
    39 } 
    40 
    41 // 在以*root为根结点的二叉树插入一个新节点 
    42 void insert(node** root, typename x) {
    43     if((*root) == NULL) {        // 找到插入位置 
    44         (*root) = newNode(x);
    45         return; 
    46     }
    47     if(x < (*root)->data) {        // 往左子树插入 
    48         insert(&((*root)->lchild), x);
    49     } else {                    // 往右子树插入 
    50         insert(&((*root)->rchild), x);
    51     }
    52 }
    53 
    54 // 二叉树的建立 
    55 node* create(typename data[], int n) {
    56     node* root = NULL;        // 新建空根结点 root 
    57     int i;
    58     for(i=0; i<n; ++i) {    // 将 data 中的数据插入二叉树 
    59         insert(&root, data[i]);
    60     } 
    61     return root;            // 返回根结点 
    62 } 
    63 
    64 // 输出二叉树,先序 
    65 void print(node* root) {
    66     if(root == NULL) {
    67         return;
    68     }
    69     printf("%d ", root->data);
    70     print(root->lchild);
    71     print(root->rchild);
    72 }
    73 
    74 int main() {
    75     int data[5] = {1, 2, 3, 4, 5};
    76     node* tree = create(data, 5);    // 创建二叉树 
    77     print(tree);                    // 输出二叉树 
    78     return 0;
    79 }
    二叉树基本操作
  • 相关阅读:
    显存与纹理内存详解
    UE4 编译虚幻引擎
    利用Lua脚本语言制作魔兽WOW插件
    详解液晶面板制造全过程
    游戏引擎剖析
    数据库常见面试题
    Selenium Webdriver元素定位的八种常用方式
    Windows 安装 Mongodb
    Redis在windows下安装过程
    python 关于一个懒惰和非懒惰的
  • 原文地址:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes20.html
Copyright © 2020-2023  润新知