C语言实现数据结构之二叉树

本博客中所有源代码:Github托管项目地址

二叉树的介绍

1、普通二叉树、完全二叉树、满二叉树

二叉树:最多有两棵子树的树被称为二叉树

满二叉树:二叉树中所有非叶子结点的度都是2,且叶子结点都在同一层次上

完全二叉树:如果一个二叉树与满二叉树前m个节点的结构相同,这样的二叉树被称为完全二叉树

也就是说,如果把满二叉树从右至左、从下往上删除一些节点,剩余的结构就构成完全二叉树


采用顺序存储的完全二叉树,可以根据任意节点的位置计算其父节点、孩子节点在数组中的位置(下标),如果父节点和孩子节点存在的话。

这也说明,完全二叉树适合使用顺序表存储



2、线索二叉树

n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。



3、哈夫曼树(最优二叉树)

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



4、二叉搜索(查找、排序)

对二叉树进行中序遍历时,其输出是一个有序数组

根据二叉排序树的定义,发现其搜索过程具有二分特性,效率较高

缺点:二叉排序树的最终形态与输入数据的顺序有关,

例如,输入数据[1,2,3,4,5,6,7,8,9],最终形成的二叉排序树如下图


此时,二叉树退化成了单链表,查找效率大大下降



5、平衡二叉树

为了克服二叉排序树的缺点,人们想出办法,使得一棵树的左右子树高度大致相等

比较出名的是苏联科学家家G.M. Adelson-Velsky 和 E.M. Landis于1962年提出的,被命名为AVL树,,和红黑树



6、AVL树

任一节点的左子树深度和右子树深度相差不超过1,我们用平衡因子衡量这种差异

任意节点的平衡因子Balance(p)= heigth(p的左子树) - height(p的右子树)

在进行AVL树的插入和删除操作时,当平衡因子=2时,就要调整节点的位置,使其满足AVL树的定义

关于AVL树的插入、删除操作,随后会进行记录



总结:我们知道,实际应用当中,我们经常使用的是查找和排序操作,这在我们的各种管理系统、数据库系统、操作系统等当中,十分常用。

数组的下标寻址十分迅速,但计算机的内存是有限的,故数组的长度也是有限的,实际应用当中的数据往往十分庞大

而且无序数组的查找最坏情况需要遍历整个数组

后来人们提出了二分查找,二分查找要求数组的构造一定有序。二分法查找解决了普通数组查找复杂度过高的问题

任和一种数组无法解决的问题就是插入、删除操作比较复杂,因此,在一个增删查改比较频繁的数据结构中,数组不会被优先考虑

普通链表由于它的结构特点被证明根本不适合进行查找

二叉查找树因为可能退化成链表,同样不适合进行查找

哈希表是数组和链表的折中,,同时它的设计依赖散列函数的设计,数组不能无限长、链表也不适合查找,所以也适合大规模的查找

AVL树的旋转过程非常麻烦,因此插入和删除很慢,也就是构建AVL树比较麻烦

红黑树是平衡二叉树和AVL树的折中,因此是比较合适的。集合类中的Map、关联数组具有较高的查询效率,它们的底层实现就是红黑树



/*bitree.h*/
#ifndef BITREE_H
#define BITREE_H
#include <stdlib.h>

/*为节点定义二叉树结构体*/
typedef struct BiTreeNode_ {
    void *data;/*存放数据*/
    struct BiTreeNode_ *left;/*左孩子*/
    struct BiTreeNode_ *right;/*右孩子*/
}BiTreeNode;
        
/*定义二叉树结构体*/
typedef struct BiTree_ {
    int size;/*存放数据个数*/
    int (*compare) (const void *key1,const void *key2);/*预留的一个接口*/
    void (*destroy)(void *data);/*封装的析构函数,作用是释放data空间*/
    BiTreeNode *root;/*指向根节点的一个指针*/
}BiTree;

/*函数接口*/
void bitree_init(BiTree *tree, void (*destroy)(void *data));
void bitree_destroy(BiTree *tree);
int bitree_ins_left(BiTree *tree,BiTreeNode *node,const void *data);
int bitree_ins_right(BiTree * tree, BiTreeNode * node, const void * data);
void bitree_rem_left(BiTree *tree,BiTreeNode *node);
void bitree_rem_right(BiTree * tree, BiTreeNode * node);
int bitree_merge(BiTree *merge,BiTree *left,BiTree *right,const void *data);

#define bitree_size(tree) ((tree) -> size)
#define bitree_root(tree) ((tree) -> root)
/*node标识是树的分子结束*/
#define bitree_is_eob(node) ((node) == NULL)
/*判断是不是叶子结点*/
#define bitree_is_leaf(node) ((node)->left == NULL && (node) ->right == NULL)
#define bitree_data(node) ((node) ->data)
#define bitree_left(node) ((node)->left)
#define bitree_right(node) ((node)->right)
#endif
/*bitree.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bitree.h"

/*二叉树初始化*/
void bitree_init(BiTree * tree, void(* destroy)(void * data))
{
    tree ->size = 0;
    tree ->destroy = destroy;
    tree ->root = NULL;
    return ;
}

/*二叉树销毁*/
void bitree_destroy(BiTree * tree)
{
    /*从二叉树中移除所有的节点*/
    bitree_rem_left( tree, NULL);

    memset(tree,0,sizeof(BiTree);
    return;
}

/* 将节点插入到二叉树中,插入到有参数指定节点的左子树
  *如果节点为空,且树为空树,就是讲此节点设为root
  * return 成功返回0,失败-1
  */

int bitree_ins_left(BiTree * tree, BiTreeNode * node, const void * data)
{ 
    BiTreeNode *new_node,**position;
    /*判断该插入到那个节点*/
    if (node == NULL){
        /*当node==NULL,说明是根节点,但是如果树不为空,则出错返回-1*/
        if (bitree_size(tree) > 0){
            return -1;
        }
        /*这个意思是position指向根节点*/
        position = &tree ->root;
    } else {
        /*判断node节点左孩子是否为空*/
        if (bitree_left(node) != NULL){
            return -1;
        }
        position = &node->left;
    }
    /*申请node空间保存data*/
    if ((new_node = (BiTreeNode *)malloc(sizeof(BiTreeNode))) == NULL)
        return -1;

    /*将节点插入到二叉树中*/
    new_node ->data = (void *)data;
    new_node ->left = NULL;
    new_node ->right = NULL;

    tree->size ++;

    return 0;
}

/*将节点插入到二叉树中,插入到有参数指定节点的右子树
  *如果节点为空,且树为空树,就是讲此节点设为root
  * return 成功返回0,失败-1
  */
  
int bitree_ins_right(BiTree * tree, BiTreeNode * node, const void * data)
{
    BiTreeNode *new_node,**position;
    /*判断该插入到那个节点*/
    if (node == NULL){
        /*当node==NULL,说明是根节点,但是如果树不为空,则出错返回-1*/
        if (bitree_size(tree) > 0){
            return -1;
        }
        /*这个意思是position指向根节点*/
        position = &tree ->root;
    } else {
            /*判断node节点左孩子是否为空*/
        if (bitree_right(node) != NULL){
            return -1;
        }
        position = &node->right;

    }
        /*申请node空间保存data*/
    if ((new_node = (BiTreeNode *)malloc(sizeof(BiTreeNode))) == NULL)
        return -1;
    
    /*将节点插入到二叉树中*/
    new_node ->data = (void *)data;
    new_node ->left = NULL;
    new_node ->right = NULL;
    *position = new_node;
    tree->size ++;
    
    return 0;

}

/*移除node节点的左孩子如果node=NULL 则移除所有节点
  *无返回值
  */
void bitree_rem_left(BiTree * tree, BiTreeNode * node)
{
    BiTreeNode **position;
    /*当为空树时返回*/
    if (bitree_size(tree) == 0)
        return;
    /* 决定删除那个节点*/
    if (node == NULL)
        position = &tree ->root;
    else 
        position = &node->left;
    /*删除这个节点*/
    if (*position != NULL){
        bitree_rem_left(tree, *position);
        bitree_rem_right(tree, *position);

        if (tree->destroy != NULL)
            tree->destroy(*position -> data);
    }
    free(*position);
    *position = NULL;

    tree->size --;
    
}
/*移除node节点的右孩子如果node=NULL 则移除所有节点
  *无返回值
  */
void bitree_rem_right(BiTree * tree, BiTreeNode * node)
{
    BiTreeNode **position;
    /*当为空树时返回*/
    if (bitree_size(tree) == 0)
        return;
    /* 决定删除那个节点*/
    if (node == NULL)
        position = &tree ->root;
    else 
        position = &node->right;
    /*删除这个节点*/
    if (*position != NULL){
        bitree_rem_left(tree, *position);
        bitree_rem_right(tree, *position);

        if (tree->destroy != NULL)
            tree->destroy(*position -> data);
    }
    free(*position);
    *position = NULL;

    tree->size --;
    

}

/*合并二叉树*/
int bitree_merge(BiTree * merge, BiTree * left, BiTree * right, const void * data)
{
    /*初始化merger*/
    bitree_init(merge, left->destroy);
    /*如何插入失败则返回-1*/
    if (bitree_ins_left(merge, NULL,  data) != 0){
        bitree_destroy(merge);
        return -1;
    }

    bitree_root(merge)->left = bitree_root(left);
    bitree_root(merge)->right = bitree_root(right);

    merge->size += bitree_size(left) + bitree_size(right);

    left ->root = NULL;
    left->size = 0;
    right->root = NULL;
    right ->size = 0;

    return 0;
    
}


二叉树头文件bistree.h

/*bistree.h*/
#ifndef BISTREE_H
#define BISTREE_H

/*定义平衡因子为AVL树*/
#define  AVL_LFT_HEAVY               1
#define  AVL_BALANCED                0
#define  AVL_RGT_HEAVY             -1

/*定义AVL树的节点*/

typedef struct AvlNode_ {
    void *data;
    int hidden;
    int factor;/*平衡因子*/
}AvlNode;

/*定义二叉树结构体*/
typedef struct BisTree_ {
    int size;/*存放数据个数*/
    int (*compare) (const void *key1,const void *key2);/*预留的一个接口*/
    void (*destroy)(void *data);/*封装的析构函数,作用是释放data空间*/
    BiTreeNode *root;/*指向根节点的一个指针*/
}BisTree;

/*函数接口*/
void bistree_init (BisTree *tree, int (*compare)(const void *key1,const void 
                               *key2),void (*destroy)(void *data));
void bistree_destory(BisTree *tree);
int bistree_insert(BisTree *tree,const void *data);
int bistree_remove (BisTree *tree,const void *data);
int bistree_lookup(BisTree *tree,void **data);
#define  bistree_size(tree)  ((tree)->size)


#endif


二叉树主文件bistree.c(旋转)
/*bistree.c*/
#include <stdlib.h>
#include <string.h>
#include "bistree.h"
#include "bitree.h"

/*左旋*/
static void rotate_left(BiTreeNode **node)
{
    BiTreeNode *right ,grandchild;
    right = bitree_right(*node);

    if (((AvlNode *)bitree_data(right) ->factor == AVL_RGT_HEAVY){
        /* RR */
        bitree_right(*node) = bitree_left(right);
        bitree_left(right) = *node;
        ((AvlNode *)bitree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED;
        *node = right;
        
    } else { /*RL*/
        grandchild = bitree_left(right);
        bitree_left(right) = bitree_right(grandchild);
        bitree_right(grandchild) = right;
        bitree_right(*node) = bitree_left(grandchild);
        bitree_left(grandchild) = *node;

        switch (((AvlNode *)bitree_data(grandchild)) ->factor){
            case AVL_LFT_HEAVY:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED;
                ((AvlNode *)bitree_data(right)) ->factor = AVL_RGT_HEAVY;
                break;
                
            case AVL_BALANCED:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED;
                ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED;
                break;
                
            case AVL_RGT_HEAVY:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_LFT_HEAVY;
                ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED;
                break;
                
            default:
                break;
        }
        ((AvlNode *)bitree_data(grandchild)) ->factor = AVL_BALANCED;
        *node = grandchild;
    }
    return;
}
/*右旋*/
static void rotata_right(BiTreeNode **node)
{
    BiTreeNode *left ,grandchild;
    left = bitree_left(*node);


    if (((AvlNode *)bitree_data(left) ->factor == AVL_LFT_HEAVY){
        /* LL */
        bitree_left(*node) = bitree_right(left);
        bitree_right(left) = *node;
        ((AvlNode *)bitree_data(*node))->factor = AVL_BALANCED;
        ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED;
        *node = left;
        
    } else { /*LR*/
        grandchild = bitree_right(left);
        bitree_right(left) = bitree_left(grandchild);
        bitree_left(grandchild) = left;
        bitree_left(*node) = bitree_right(grandchild);
        bitree_right(grandchild) = *node;


        switch (((AvlNode *)bitree_data(grandchild)) ->factor){
            case AVL_LFT_HEAVY:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_RGT_HEAVY;
                ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED;
                break;
                
            case AVL_BALANCED:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED;
                ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED;
                break;
                
            case AVL_RGT_HEAVY:
                ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED;
                ((AvlNode *)bitree_data(left)) ->factor = AVL_LFT_HEAVY;
                break;
                
            default:
                break;
        }
        ((AvlNode *)bitree_data(grandchild)) ->factor = AVL_BALANCED;
        *node = grandchild;
    }
    return;
}

书中代码略晦涩难懂。

猜你喜欢

转载自blog.csdn.net/shiyipaisizuo/article/details/79015270
今日推荐