二叉树的创建以及四种遍历方式

1.树

树形结构:一对多,第一个节点没有前驱,最后一个节点没有后继,中间节点有唯一前驱,可以有多个后继,也可以没有

2.树的概念

由m(>=0)个互不相交的有限集合组成的集合

一个节点的子树个数称为该节点的度数。树的度数由树中最大的度数来决定。

度数为0的节点称为树叶,叶节点或终端节点。度数不为0的称为分支节点,除了根节点以外的分支节点称为内部节点。

路径:路径上的节点ki是ki+1的父节点(叶节点的个数也就是路径的个数)路径的长度称为边数。

层数:同一父节点的节点为同一层。根节点为第一层,树中节点的最大层数称为树的高度或者深度

树的左右节点有序,从左到右不可交换,则称为有序树

m(m>=0)棵互不相交的树的集合称为森林。树去掉根节点就称为森林

兄弟分为:亲兄弟,堂兄弟

3.二叉树

二叉树的定义:二叉树是n(n>=0)个节点的有限集合,它或者是空集(n=0),或者是由一个根节点以及两棵不互相交的、分别称为左子树与柚子树的二叉树组成,二叉树与普通有序树不同,二叉树严格区分左孩子和右孩子,即使只有一个节点也要区分左右,度数最大为2.

性质:

第i层上的节点最多为2^(i-1)

知道最大层数,总的节点最多为2^i-1

树叶的数目比度数为2的节点的数目多1

(n0表示没有子节点的节点总数,n1表示有一个子节点的节点总数,n2表示有两个子节点的节点总数)

n=n0+n1+n2①        

n=n1+2*n2+1②

n0=n2+1

满二叉树,每一层的孩子都存满(可以顺序存储,空间不浪费)

完全二叉树:只有最下面两层有度数小于2的节点,只有一个孩子时,孩子为左孩子

4.二叉树的顺序存储

先将二叉树补成完全二叉树,再从上到下,从左到右将所有节点编号,依次存放在缓冲区中。

完全二叉树节点编号,从上到下,从左到右,根节点为一号,设节点数为n,某编号为i。

性质:

当i>1时,有父节点,其编号为i/2;

当2* i<=n时,有左孩子,其编号为2*i,否则没有左孩子,本身是叶节点;

当2* i+1<=n时,有右孩子,其编号为2*i+1,否则没右孩子,本身是叶节点;

当i为奇数(右节点)且不为1时,有左兄弟,其编号为i-1,否则没有左兄弟;

当i为偶数(左节点)且小于n时,有右兄弟,其编号为i+1,否则没有右兄弟

/*===============================================
*   文件名称:seqtree.c
*   创 建 者:     
*   创建日期:2022年08月02日
*   描    述:
================================================*/
#include <stdio.h>

int main(int argc, char *argv[])
{ 
    char buf[16]={0},ch,i=1,n=1;
    printf("请输入完全二叉树的元素(#结束)\n");
    while((ch=getchar())!='#')//一个一个输入
    {
        buf[i]=ch;
        i++;
    }
    for(i=0;i<16;i++)//显示
    {
        if(i>n-1)
        {
            puts("");
            n=2*n;
        }
        if(buf[i]=='@')
        {
            printf(" ");
            continue;
        }
        printf("%c",buf[i]);
    }

    puts("");
    return 0;
} 

 5.树的链式存储

树中每个节点相关的结构体:

typedef int data_t;
typedef struct tree_node
{
    data_t data;//数据域
    struct tree_node *l_child;//左节点
    struct tree_node *r_child;//右节点
}T_node;

6.二叉树的遍历

先序遍历:根左右

中序遍历:左根右

后序遍历:左右根

二叉树的层次遍历:

根先入队,然后循环到队列为空。

入队:判断一次根的左右节点是否存在,存在就入队(先左后右)

出队:打印根的数据域,根出队

6.1头文件

头文件定义了树的存储类型,结构体的设计,以及将要实现的功能函数。

/*===============================================
*   文件名称:linktree.h
*   创 建 者:     
*   创建日期:2022年08月02日
*   描    述:
================================================*/

#ifndef __LINKTREE__
#define __LINKTREE__

typedef char data_t;
typedef struct tree_node
{
    data_t data;
	struct tree_node *l_child;
	struct tree_node *r_child;
}T_node;

T_node *Create_Linktree();//创建一个二叉树

void Linktree_Show0(T_node *root);//先序遍历

void Linktree_Show1(T_node *root);//中序遍历

void Linktree_Show2(T_node *root);//后序遍历

void Nooread(T_node *root);//层次遍历

#endif

6.2功能函数

二叉树的难点在于创建时的递归调用。从终端输入一串数据以 '#' 结束,数据存储在缓冲区中,然后每次执行创建程序,读一个字符。判断是否是'#',如不是,则向堆区申请空间,把数据存入数据域,指针域则调用创建函数,形成递归,先创建左子树,再创建右子树,当读取到'#'时,标明没有子树。返回NULL。

三种常见的遍历方式先判断是否是空树,不是的话就按照对应的顺序来调用遍历函数,形成递归条件,都是在根节点时打印。

        

最后的层次遍历则利用到了队列,每一个根节点都判断是否有左右子树,有的话就入队,然后把队列的第一个节点也就是这一次循环的根节点打印,然后出队,因为只显示一遍,不需要循环队列。

/*===============================================
*   文件名称:linktree.c
*   创 建 者:     
*   创建日期:2022年08月02日
*   描    述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
#include "linktree.h"

T_node *Create_Linktree()//创建一个二叉树
{
	char x;
	//printf("请输入节点的值,#表示空\n");
	T_node *root;
	scanf("%c",&x);
	//printf("x=%c\n",x);
	//getchar();
	if(x!='#')
	{
		root=(T_node *)malloc(sizeof(T_node));
		if(NULL==root)
		{
			printf("nalloc error");
			return NULL;
		}
		root->data=x;	
		root->l_child=Create_Linktree();//先左后右
		root->r_child=Create_Linktree();
		return root;
	}
	else
	{
		return NULL;
	}
} 

void Linktree_Show0(T_node *root)//先序遍历
{
	if(root!=NULL)		//根
	{
		printf("%4c",root->data);

		Linktree_Show0(root->l_child);//左	
	
		Linktree_Show0(root->r_child);//右
	}
	return;
	
}
void Linktree_Show1(T_node *root)//中序遍历
{
	if(root!=NULL)		//根
	{
		Linktree_Show0(root->l_child);//左	
		printf("%4c",root->data);
		Linktree_Show0(root->r_child);//右
	}
	return;
	
}
void Linktree_Show2(T_node *root)//后序遍历
{
	if(root!=NULL)		//根
	{
		Linktree_Show0(root->l_child);//左	
	
		Linktree_Show0(root->r_child);//右
		
		printf("%4c",root->data);
	}
	return;
}
void Nooread(T_node *root)//层次遍历
{
	int front,rear;//头尾指针
	T_node *q[16];    //指针数组
	if(root==NULL) //判断树是否为空
	{
		printf("空树无法遍历\n");
		return;
	} 
	for(rear=1;rear<16;rear++)//给指针数组赋初值NULL
	{
		q[rear]=NULL;
	}
	front=rear=1;//下标为0的数组元素不用
	q[rear]=root;
	rear++;
	while(q[front]!=NULL)//队列为空则跳出循环
	{
		if(q[front]->l_child!=NULL)//左孩子存在则入队
		{
			q[rear]=q[front]->l_child;
			rear++;	//rear后移
		}
		if(q[front]->r_child!=NULL)//右孩子存在则入队
		{
			q[rear]=q[front]->r_child;
			rear++;	//rear后移
		}
		printf("%c",q[front]->data);//打印出队节点
		front++;		//队头节点出队
	}
}

6.3主函数

主函数就调用了功能函数,先是创建了二叉树,然后四种遍历方式输出

/*===============================================
*   文件名称:main.c
*   创 建 者:     
*   创建日期:2022年08月02日
*   描    述:
================================================*/
#include <stdio.h>
#include "linktree.h"

int main(int argc, char *argv[])
{ 
	T_node *root=Create_Linktree();
	printf("-------------------------------------------\n");
	Linktree_Show0(root);
	printf("\n-------------------------------------------\n");
	Linktree_Show1(root);
	printf("\n-------------------------------------------\n");
	Linktree_Show2(root);
	printf("\n-------------------------------------------\n");
	Nooread(root);
	puts("");
    return 0;
} 

 

 

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值