之前写了好多篇文章关于数据结构的,既然讲到了数据结构,那么就必须要说一下树,树这个数据结构使用范围非常广,应用前景广阔。
关联文章:
五分钟搞懂什么是红黑树(全程图解)
Linux 内核红黑树分析
这篇文章主要是讲解最简单的一个树的构成,并用代码实现。
声明节点结构体
/*树节点*/
typedef struct node{
	int data;
	struct node * left; /*节点左边的树枝*/
	struct node * right;/*节点右边的树枝*/
}Node;
data 是这个节点的数据,left是这个节点指向左边节点的指针,right 是指向右边节点的指针。
声明根节点结构体
/*树根*/
typedef struct tree{
	Node * root;
}Tree;
根节点也是一个节点,只不过这个节点代表了这棵树,这个节点存在,就代表这棵树没有死。
定义一个根节点
	Tree tree;
    tree.root = NULL;/*创建一个空树*/
像节点插入一个数据
我们现在模拟一下,插入一个数据 5
/*插入函数 向一个树里面插入数据*/
void insert(Tree* tree, int value)
{
	/*创建一个节点*/
    Node* node=(Node*)malloc(sizeof(Node));
    node->data = value;
    node->left = NULL;
    node->right = NULL;
    
    /*判断树是不是空树*/
    if (tree->root == NULL)
    {
        tree->root = node;
    }
    //.......
}
我们会先判断 这个树是不是空的,如果是空的,就把这树根指向这个 node 节点。
我们再插入一个数据 4
因为 4 小于 5,所以我们需要把 4插入到 5 的左边节点去。
insert(&tree, temp);
所以就变成这样
我们再插入一个数据 3
因为 3 小于 4,那我们就再插入到4的left节点。
如果我们再插入一个 5呢?
大于等于 当前节点的,都进入right节点,所以,插入 5 会变成这样。
遍历一棵树
遍历一棵树的方法有很多,前序遍历,中序遍历,后序遍历,我这里就不说了,无非就是递归判断节点是否为空,我这里使用的是中序遍历。
/*
 遍历一整颗树
 中序遍历:先左后根再右
 */
void traverse(Node* node)
{
    if(node != NULL)
    {
        traverse(node->left);
        printf("%d ",node->data);
        traverse(node->right);
    }
}
traverse(node->left); 递归扫描所有的左子树节点 traverse(node->right); 递归扫描所有的右子树节点
销毁一棵树
既然我们是通过 malloc 来创建一棵树的,那么使用完后,肯定需要释放内存,要不然内存就会一直消耗占用。
/*销毁一棵树*/
void distory_tree(Node* node)
{
	
	if(node != NULL)
	{
		distory_tree(node->left);
        distory_tree(node->right);
        printf("free node:%d\n",node->data);
		free(node);
		node = NULL;
	}
}
使用递归很爽啊,一直使用一直爽啊。哈哈,那就一直使用递归好了。
完整代码
#include "stdio.h"
#include "stdlib.h"
/*树节点*/
typedef struct node{
	int data;
	struct node * left; /*节点左边的树枝*/
	struct node * right;/*节点右边的树枝*/
}Node;
/*树根*/
typedef struct tree{
	Node * root;
}Tree;
/*插入函数 向一个树里面插入数据*/
void insert(Tree* tree, int value)
{
	/*创建一个节点*/
    Node* node=(Node*)malloc(sizeof(Node));
    node->data = value;
    node->left = NULL;
    node->right = NULL;
    
    /*判断树是不是空树*/
    if (tree->root == NULL)
    {
        tree->root = node;
    }
    else /*不是空树*/
	{
        Node* temp = tree->root;/*从树根开始*/
        while (temp != NULL)
        {
            if(value < temp->data)/*小于就进左儿子*/
            {
                if(temp->left == NULL)
                {
                    temp->left = node;
                    return;
                }
                else /*继续判断*/
				{
                    temp = temp->left;
                }
            }
            else /*否则进右儿子*/
			{
 
                if(temp->right == NULL)
                {
                    temp->right = node;
                    return;
                }
                else /*继续判断*/
				{
                    temp = temp->right;
                }
            }
        }
    }
}
/*
 遍历一整颗树
 中序遍历:先左后根再右
 */
void traverse(Node* node)
{
    if(node != NULL)
    {
        traverse(node->left);
        printf("%d ",node->data);
        traverse(node->right);
    }
}
/*销毁一棵树*/
void distory_tree(Node* node)
{
	
	if(node != NULL)
	{
		distory_tree(node->left);
        distory_tree(node->right);
        printf("free node:%d\n",node->data);
		free(node);
		node = NULL;
	}
}
/*主函数*/
int main()
{
	int i = 0;
	Tree tree;
    tree.root = NULL;/*创建一个空树*/
    int n;
    printf("input total num:\n");
    /*输入n个数并创建这个树*/
    scanf("%d",&n);
    for(i = 0; i < n; i++)
    {
        int temp;
        scanf("%d",&temp);
        insert(&tree, temp);
    }
    /*遍历整个树*/
    traverse(tree.root);
	
	/*销毁一棵树*/
	distory_tree(tree.root);
	return 0;
}
总结
数据结构里的树是一个难点和重点,变化也非常多,我们安卓系统里面的跨进程间通信,使用的binder,底层就是有使用到红黑树,大家如果通过这个小例子知道树这个概念,以后遇到就不至于一愣一愣的。
好吧,就说这么多,文章有问题的,欢迎批评指正,我们要在批评与指正中成长,觉得不错的,感谢转发和再看。
共勉~
—————END—————