C语言:利用排序二叉树进行排序

C语言:利用排序二叉树进行排序

标签: C语言 二叉树 排序

by 小威威


1.引入

排序二叉树属于二叉树的一种,其主要特色在于构建二叉树与输出二叉树。二叉树的子树很有特点:左子树小于根结点,根结点小于右子树。通过排序二叉树,我们可以了解二叉树三种遍历的其中两种:即是中序遍历后序遍历。

中序遍历:中序遍历就是先读取左子树,再读取根结点,最后再读取右子树。
后序遍历:后序遍历就是先读取左子树,再读取右子树,最后再读取根结点。

补充:先序遍历就是先读取根结点,再读取左子树,最后再读取右子树。

2.代码

先上代码:
代码主要分为两部分:第一部分是main函数部分,第二部分是二叉树功能实现的部分。

/*main.h*/
#include<stdio.h>
#include<stdlib.h>
#include"tree.h"

int main(void) {
    int node_num, i = 0, temp;
    Node *root = NULL;
    scanf("%d", &node_num);
    while (i < node_num) {
        scanf("%d", &temp);
        if (i == 0) root = init_root(temp);
        else insert_node(root, temp);
        i++;
    }
    traverse_tree_inorder(root);
    printf("\n");
    recycle_nodes(root);
    return 0;
}

 /*tree.h*/
 # include <stdlib.h>
# include <stdio.h>
typedef struct Node {
    struct Node *left;
    struct Node *right;
    int value;
} Node;
Node* init_root(int value) {
    Node *root;
    root = malloc(sizeof(Node));
    root->value = value;
    root->left = NULL;
    root->right = NULL;
    return root;
}
void insert_node(Node *p, int value) {
    Node *pArr;
    pArr = malloc(sizeof(Node));
    pArr->value = value;
    pArr->left = NULL;
    pArr->right = NULL;
    while (p->left != pArr && p->right != pArr) {
        while (value > p->value) {
            if (p->right == NULL) {
                p->right = pArr;
                return;
            } else {
                p = p->right;
            }
        }
        while (value < p->value) {
            if (p->left == NULL) {
                p->left = pArr;
                return;
            } else {
                p = p->left;
            }
        }
    }
    return;
}
void traverse_tree_inorder(Node *p) {
    if (p == NULL)
        return;
    traverse_tree_inorder(p->left);
    printf("%d ", p->value);
    traverse_tree_inorder(p->right);
}
void recycle_nodes(Node *p) {
    if (p == NULL)
        return;
    recycle_nodes(p->left);
    recycle_nodes(p->right);
    free(p);
}

本题的核心就是写tree.h的头文件。
该头文件需要实现以下函数:

/*中序遍历这个二叉树,按照升序输出,每个数之间有一个空格,最后一个数后也有一个空格。*/
void traverse_tree_inorder(Node *p)

/*回收建立二叉树时开辟的内存空间,提示类似后序遍历。*/
void recycle_nodes(Node *p);

/*将一个值为value的数插入到这个树中,但是要注意,需要插到那个地方,按照排序二叉树的要求来。*/
void insert_node(Node *p, int value);

/*初始化根节点的值。*/
Node* init_root(int value);

首先是初始化根结点的值的函数:

Node* init_root(int value) {
    Node *root;
    root = malloc(sizeof(Node));
    root->value = value;
    root->left = NULL;
    root->right = NULL;
    return root;
}

这个函数很简单,只需给根结点开辟一个空间后初始化即可。注意,要把结点内的左右指针置为空。

其次是构建二叉树,这是本题的难点。

void insert_node(Node *p, int value) {
    Node *pArr;
    pArr = malloc(sizeof(Node));
    pArr->value = value;
    pArr->left = NULL;
    pArr->right = NULL;
    while (p->left != pArr && p->right != pArr) {
        while (value > p->value) {
            if (p->right == NULL) {
                p->right = pArr;
                return;
            } else {
                p = p->right;
            }
        }
        while (value < p->value) {
            if (p->left == NULL) {
                p->left = pArr;
                return;
            } else {
                p = p->left;
            }
        }
    }
    return;
}

这种构建二叉树的方法我称它为插入构造法。即将元素插入正确的位置。这种插入使得中序遍历输出一串有顺序的数字。那么,怎么插?

举个例子:
输入这些数据:23, 3, 53, 333, 2
输出: 2, 3, 23, 53, 333

第一个数字一定是给根结点赋值,所以不用判断。但接下来的数字都要进行判断,进而插入合适的位置。第二个数字3,将3与23比较,发现3小于23,所以将3成为23的左儿子。第三个数字53,将53与23比较,发现53大于23,因此53作为23的右儿子。第四个数字333,将333与23比较,发现333大于23,然而23的右儿子已经存在了,因此将333与23的右儿子53进行比较,发现333大于23,因此将333作为53的右儿子。第五个数字2,将其与23比较,发现2小于23,然而23的左儿子已经存在,因此将2与23的左儿子3比较,发现2小于3,因此将2作为3的左儿子。如此,排序二叉树就这样建立起来了。
你们可以通过这个例子了解插入的原理,然后自己用代码实现出来。

然后我要讲第三个函数中序遍历输出二叉树:

void traverse_tree_inorder(Node *p) {
    if (p == NULL)
        return;
    traverse_tree_inorder(p->left);
    printf("%d ", p->value);
    traverse_tree_inorder(p->right);
}

对于二叉树的遍历,我们一般通过递归实现,左子树一个递归,右子树一个递归,还有一个额外的操作。中序遍历就是先左子树的递归,再额外的操作,最后再右子树的递归。后序遍历也是这样,先左子树的递归,后右子树的递归,最后再额外的操作。前序遍历以此类推。此处的额外操作就是输出操作。

最后我要讲的是第四个函数:释放二叉树

void recycle_nodes(Node *p) {
    if (p == NULL)
        return;
    recycle_nodes(p->left);
    recycle_nodes(p->right);
    free(p);
}

因为二叉树的各个结点都是通过动态分配内存得来的,因此在程序终止前要将这些结点所分配的内存全部释放。不难发现其实释放的原理便是后序遍历。这里额外的操作就是释放内存,即free()。

3.总结

其实二叉树很好玩,只要你搞懂原理哈哈~

先序遍历:对一棵二叉树的前序遍历,先访问根结点,再访问左子树,然后访问右子树。

void preorder(Treenode *p) {

    if (p!=NULL){

        visit(p);

        preorder(p->left);

        preorder(p->right);

    }

}

中序遍历:对一棵二叉树的中序遍历,先访问左子树,再访问根结点,然后访问右子树。

void inorder(Treenode *p) {

    if (p!=NULL){

        inorder(p->left);

        visit(p);

        inorder(p->right);

    }

}

后序遍历:对一棵二叉树的后序遍历,先访问左子树,再访问右子树,然后访问根结点。

void postorder(Treenode *p) {
    if (p!=NULL){

        postorder(p->left);

        postorder(p->right);

        visit(p);

    }

}

以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!


  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值