数据结构05----C语言树

前面几节的内容,链接如下:
单链表
双链表

队列
查找排序算法

今天我们来看看数据结构中的另外一个重要内容:树

六、树

前面我们学习的都是线性结构,现在说的树属于一种非线性结构。树的模型,类似于一个家族的族谱,相信不用多说,大家就可以想象出他的样子。
1.树的定义
树是n(n>=0)个元素的有限集合。当n = 0时,称为空树。当n>0 时,则在这颗树中的结点有如下特征:
①有且仅有一个特定的称为根(root)结点,他只有直接后继,但是没有直接前驱;
②当n>1时,其余结点可分为m(m>0)个互不相交的有限集合,其中每个集合本身又是一棵树,并且称为根的子树。每颗子树的根结点有且只有一个直接前驱,即根结点root,但可以有0或多个直接后继。
如下图:
在这里插入图片描述
(a)(b)都好理解,看看(c),他有12个结点,其中A为根结点,其余的结点分为3个互不相交的子集,T1 = {B,E,F},T2 = {C,G,K,L},T3 = {D,H,I,J}。T1、T2和T3都是根A的子树,且本身也是一棵树。比如T1,其根为B,其余结点分为2个互不相交的子集,T11 = {E},T12 = {F}。T12和T11都是根B的子树,T11中E是根,T12中F是根。依次类推。

2.几个重要的术语
(以上面©为例讲解)
结点:树中每一个元素就是一个结点,如上面有12个结点;

结点的度:结点拥有的子树数目。如上面结点A的度为3;

树的度:树中所有结点的度的最大值,如上面树的度为3;

叶子结点:度为0的结点,简称叶结点、终端结点、外部结点,如上图中E/F/H/I/J/K/L都是叶结点;

分支结点:度大于0的节点,就是除了叶子结点外的其他结点都是分支结点;

树的高度:如上图©,他的高度为4;

孩子结点和双亲结点:
结点的层次:
兄弟结点:
堂兄弟结点:
祖先结点:
子孙结点:
上面几个没有解释的结点,应该都是很好理解的,按照字面上理解就好,他们并不重要,我们只需要知道有这些概念即可。若是有读者想知道,自己查阅即可。

路径:就是一个结点到另外一个结点的分支;

有序树:树中结点的各子树看成从左到右是有次序的,即子树之间存在着确定的次序关系,这样的树称为有序树;

无序树:根结点的各课子树之间存在不确定的次序关系,可以相互交换位置,称为无序树;

森林:m(m>=0)颗互不相交的树的集合构成森林。

3.二叉树
任何树和森林都可以转化为二叉树,比较适合计算机处理。二叉树是我们要学习掌握的重点。

二叉树的基本形态如下:
在这里插入图片描述
所谓的二叉树,只不过实在树的基础上做了更高的限制,规定,二叉树中各个结点的度最大为2.

这里也有两个个概念:
满二叉树:只含有度为0和2的结点,且度为0的结点只存在于最后一层的二叉树。
完全二叉树:对任意一颗满二叉树,从他的最后一层的最右边结点起,按照从上到下,从右到左的次序,去掉若干结点后,得到的二叉树

如下图:
在这里插入图片描述
完全二叉树的性质:
设完全二叉树结点数为n,将各结点从左到右依次标号,根节点为1,某结点为i。则:
当i>1时,父节点为结点i/2
当2i>n时,则结点i肯定没有左孩子,否则左孩子是2i
当2i+1>n,则结点i肯定没有右孩子,否则右孩子是结点2i+1

二叉树的存储:顺序存储与链式存储;
顺序存储:
用数组将二叉树中数据元素存储起来,此方法只适用于完全二叉树,如果想存储普通二叉树,需要将其转化为完全二叉树。
有n个结点的完全二叉树,用有n+1个元素的数组进行顺序存放,结点号和数组下标一一对应,下标为零的元素不用。

例:找到族谱中"li"的父亲是谁?如下图:
在这里插入图片描述
程序如下:

#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[])
{
	char a[10][10]={"#","zhao","qian","sun","li","zhou","wu","zheng","wang","qwe"};

	int i;
	for(i=0;i<10;i++)
	{
		if (strcmp(a[i],"li")==0)
		{
			printf("%s\n",a[i/2]);
			break;
		}
	}
	return 0;
}

运行结果:
在这里插入图片描述

链式存储:
结点:

typedef struct Node
{
	int data;
    struct Node *lchild,rchild;
}node;

二叉树遍历:
沿某条搜索路径周游二叉树,对树的每个结点访问且仅访问一次。

二叉树三种遍历方式:使用递归的思想
先序遍历:先访问根节点,在遍历左右子树
中序遍历:遍历左子树,访问根节点然后遍历右子树
后序遍历:遍历完左右子树,在访问根节点

最后我们来看看例程:
编程练习:
定义结点;
建立树; 先序输入
三种遍历;
如下图:
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

//1、定义树的结点
typedef struct Node
{
	char data;
	struct Node *lchild,*rchild;
}node;


//2、创建树
void create_tree(node **head)
{
	char ch;
	scanf("%c",&ch);

	if (ch=='#')
	{
		*head=NULL;
	}
	else
	{
		*head=(node *)malloc(sizeof(node));
		(*head)->data=ch;

		create_tree(&((*head)->lchild));   //先存储左边的
		create_tree(&((*head)->rchild));
	}

}

//3、先序遍历
void pre_order(node *head)
{
	if (head!=NULL)
	{
		printf("%c  ",head->data);
		pre_order(head->lchild);
		pre_order(head->rchild);
	}
}

//3、中序遍历
void mid_order(node *head)
{
	if (head!=NULL)
	{
		mid_order(head->lchild);
		printf("%c  ",head->data);
		mid_order(head->rchild);
	}
}

//3、后序遍历
void lat_order(node *head)
{
	if (head!=NULL)
	{
		lat_order(head->lchild);
		lat_order(head->rchild);
		printf("%c  ",head->data);
	}
}

int main(int argc, char const *argv[])
{
	node *head;
	create_tree(&head);  //传址
	pre_order(head);
	printf("\n");

	mid_order(head);
	printf("\n");

	lat_order(head);
	printf("\n");
	
	return 0;
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

all of the time

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值