二叉树的顺序结构C语言实现


顺序存储结构--将二叉树按层序依次存入数组中


已知一个节点在数组中序号为i,则该节点的

双亲节点序号为:((i+1)/2)-1

左孩子:         2*i+1

右孩子:         2*i+2


代码实现关键点:


1.创建二叉树CreateBiTree():按层次顺序输入二叉树中节点的值

1)对非空无双亲的非根节点的判断   if(i!=0&&T[(i+1)/2-1]==0&&T[i]!=0)

非根节点--i!=0;无双亲--T[(i+1)/2-1]=Nil;非空--T[i]=Nil

此种节点的存在不合理:除根节点外,其他非空节点都有双亲节点。如果出现 非根,非空,但又没有双亲的节点,

则该该节点不合法。


2.得到二叉树的深度BiTreeDepth

先得到节点数,然后利用二叉树性质2(深度为k的二叉树至多有(2^k)-1个节点)得到深度。


3.Assign()给处于位置(level,order)的节点赋值。(level,order)表示(层,层序),从左到右

因为二叉树第k层最多有2^(k-1)个节点,所以有对赋值节点位置越界的判断

if(level>BiTreeDepth(T)||order>(int)powl(2,level-1))

int pos = (int)powl(2,e.level-1)+e.order-2 ---将(level,order)转化为节点在数组的位置

两种不合法赋值判断:1).给叶子赋值,但是双亲为空;2).给双亲赋空值,但是其有叶子节点(非空)

1)---if(value!=Nil&&T[(pos+1)/2-1]==Nil)

2)---if(value==Nil&&(T[pos*2+1]!=Nil||T[pos*2+2]!=Nil))


3.RightSibling返回节点e的右兄弟,否则返回空

if(T[i]==e&&i%2!=0)---找到e,且i为奇数--左孩子,则其右兄弟为T[i+1]


4.三种遍历:先序,中序,后序

三者在代码上没有太大区别,只是反问局部根节点的顺序分别为:左根右、根左右、左右根

判断是否为左孩子:if(T[2*i+1]!=Nil)

判断是否为右孩子:if(T[2*i+2]!=Nil)


代码(站在巨人的肩膀上)

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

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100
#define MAX_TREE_SIZE 100


typedef int Status;
typedef int TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE];//将SqBiTree定义为元素TElemType的数组

typedef struct
{
	int level,order;
}Position;

TElemType Nil = 0;//Nil表示无值,是object-c,Ruby,Lua中的关键字

//创建空树,此处树中每个节点都为0
Status InitBiTree(SqBiTree T)
{
	for(int i = 0;i<MAXSIZE;i++)
	{
		T[i]=0;//The initial data of the tree node is zero
	}
	return OK;
}


//创建树,按层次顺序输入二叉树中节点的值
Status CreateBiTree(SqBiTree T)
{
	int i=0;
	if(NULL==T)
	{
	
		return ERROR;
	}
	printf("请按层顺序输入节点的值(整型),0表示空节点,输入0结束.节点树<%d\n",MAX_TREE_SIZE);
	while(i<20)
	{
	    T[i]=i+1;
		if(i!=0&&T[(i+1)/2-1]==0&&T[i]!=Nil)//二叉树中没有此内节点。非根节点--i!=0;无双亲--T[(i+1)/2-1]==Nil;非空节点--T[i]!=Nil
		{
			printf("出现非空的无双亲的非根节点%d\n",T[i]);
			exit(ERROR);
		}
		i++;
	}
	while(i<MAX_TREE_SIZE)
	{
		T[i] = 0;
		i++;
	}
	return OK;
}
//ClearBiTree将树的节点数据清零,相当于函数InitTree

#define ClearBiTree InitBiTree

//初始条件:二叉树存在
//操作结果:EmptyBiTree检查树是否为空,如果为空返回TRUE,否则返回FALSE
Status EmptyBiTree(SqBiTree T)
{
	if(NULL==T)
	{
		return ERROR;
	}
	if(Nil==T[0]) //根节点为空,则树为空
	{
		return TRUE;
	}
	return FALSE;
}

//初始条件:二叉树存在
//操作结果:返回树的深度(层)
int BiTreeDepth(SqBiTree T)
{
	if(NULL==T)
	{
		return ERROR;
	}
	int i,j=0;
	for(i=MAX_TREE_SIZE-1;i>=0;i--)
	{
		if(T[i]!=Nil)
		{
			break;
		}
	}
	i++; //节点数
	while(i>=powl(2,j)) //二叉树性质:深度为k的二叉树至多有(2^k)-1个节点
	{
		j++;
	}
	return j;
}

//初始条件:二叉树存在
//操作结果:得到根节点,并用e返回根,返回OK;否则返回ERROR
Status Root(SqBiTree T,TElemType *e)
{
	if(EmptyBiTree(T))
	{
		return ERROR;
	}else
	{
		*e = T[0];
		return OK;
	}
}
//初始条件:二叉树存在
//操作结果:返回指定节点的值,没有则返回ERROR;Position(层,本层序号)确定节点位置
TElemType Value(SqBiTree T,Position e)
{
	if(NULL==T)
	{
		return ERROR;
	}
	if(0==T[0])
	{
		return ERROR;
	}
	if(e.level>BiTreeDepth(T)||e.order>(int)powl(2,e.level-1))//节点不存在
	{
		return ERROR;
	}
	int pos = (int)powl(2,e.level-1)+e.order-2;//根据e确定节点在数组中的位置
	return T[pos];
}
//初始条件:二叉树存在
//操作处理:给处于e的树T的节点赋值value,没有则返回ERROR
Status  Assign(SqBiTree T,Position e,TElemType value)
{
	if(NULL==T)
	{
		return ERROR;
	}
	if(e.level>BiTreeDepth(T)||e.order>(int)powl(2,e.level-1))//位置越界
	{
		return ERROR;
	}
	int pos = (int)powl(2,e.level-1)+e.order-2;  //将Position转化为节点在数组的位置
	if(value!=Nil&&T[(pos+1)/2-1]==Nil)//给叶子赋值,但是双亲为空
	{
		return ERROR;
	}else if(value==Nil&&(T[pos*2+1]!=Nil||T[pos*2+2]!=Nil))//给双亲赋空值,但是有叶子节点(不空)
	{
		return ERROR;
	}
	T[pos] = value;
	return OK;
}

//初始条件:二叉树存在
//操作处理:返回非根节点e的双亲节点,没有则返回“空”
TElemType Parent(SqBiTree T,TElemType e)
{
	if(NULL == T)
	{
		return ERROR;
	}
	int i;
	for(i=0;i<MAX_TREE_SIZE-1;i++)//顺序结构,遍历方便
	{
		if(e==T[i])
		{
			return T[(i+1)/2-1];//找到则返回其双亲节点T[(i+1)/2-1]
		}
	}
	return Nil; //没找到则返回空
}
//初始条件:二叉树存在
//操作处理:若e是树T的非叶节点,则返回它的左孩子,否则返回空
TElemType LeftChild(SqBiTree T,TElemType e)
{
	if(NULL==T)
	{
		return ERROR;
	}
	int i;
	for(i=0;i<MAX_TREE_SIZE;i++)
	{
		if(e==T[i])
		{
			return T[i*2+1];//找到返回其左孩子
		}
	}
	return Nil;
}
//初始条件:二叉树存在
//操作处理:返回节点e的右兄弟,否则返回空
TElemType RightSibling(SqBiTree T,TElemType e)
{
	if(NULL==T)
	{
		return ERROR;
	}
	if(Nil==T[0])
	{
		return Nil;
	}
	int i;
	for(i=0;i<=MAX_TREE_SIZE-1;i++)
	{
		if(T[i]==e&&i%2!=0)//找到e,且i为奇数--左孩子
		return T[i+1];
	}
	return Nil;
	
}
//访问某个节点--打印节点值
Status visit(TElemType c)
{
	printf("%d ",c);
	return OK;
}
//先序遍历:被调函数
void PreTraverse(SqBiTree T,int i)
{
	visit(T[i]); //访问根节点
	if(T[2*i+1]!=Nil) //如果有左孩子,先访问左孩子
	{
		PreTraverse(T,2*i+1);
	}
	if(T[2*i+2]!=Nil)//如果有右孩子,后访问右孩子
	{
		PreTraverse(T,2*i+2);
	}
}

//初始条件:二叉树存在
//操作处理:先序遍历树T
Status PreOrderTraverse(SqBiTree T)
{
	if(!EmptyBiTree(T))
	{
		PreTraverse(T,0);
	}
	printf("\n");
	return OK;
}

//中序遍历:被调函数。思路同PreTraverse
void InTraverse(SqBiTree T,int i)
{
	if(T[i*2+1]!=Nil)
	{
		InTraverse(T,i*2+1);
	}
	visit(T[i]);
	if(T[i*2+2]!=Nil)
	{
		InTraverse(T,i*2+2);
	}
}
//初始条件:二叉树存在
//操作处理:中序遍历树T
Status InOrderTraverse(SqBiTree T)
{
	if(!EmptyBiTree(T))
	{
		InTraverse(T,0);
	}
	printf("\n");
	return OK;
}


int main()
{
	SqBiTree T;
	CreateBiTree(T);
	/*返回树的深度*/
	int depth =	BiTreeDepth(T);
	printf("深度:%d\n",depth);

	/*返回特定位置的节点的值*/
	printf("返回特定位置的节点值---输入节点位置:\n");
	Position e;
	scanf("%d %d",&e.level,&e.order);
	TElemType value = Value(T,e);
	printf("处于位置e的节点值为:%d\n",value);
    
	/*给特定节点赋值*/
	printf("给特定节点赋值---输入节点位置:\n");
	Position pos;
	scanf("%d %d",&pos.level,&pos.order);
	Status sts = Assign(T,pos,4);
	if(OK==sts)
	{
		printf("节点e被赋值为:%d\n",T[(int)powl(2,pos.level-1)+pos.order-2]);
	}else
	{
		printf("赋值失败!\n");
	}

	/*返回双亲节点*/
	printf("返回双亲节点---输入节点值:\n");
	TElemType c;
	scanf("%d",&c);
	TElemType parent = Parent(T,c);
	printf("双亲节点值为:%d\n",parent);

	/*返回右兄弟*/
	printf("返回右兄弟节点---输入节点值:\n");
	TElemType d;
	scanf("%d",&d);
	TElemType rightsibling = RightSibling(T,d);
	printf("右兄弟节点值为:%d\n",rightsibling);

	/*先序遍历*/
	PreOrderTraverse(T);

	/*中序遍历*/
	InOrderTraverse(T);

}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值