数据结构学习笔记 --- 树

1. 引言


一棵树无论有多少叉,它最多有一个长子和一个排序恰在其下的兄弟。根据这样的定义,则每个结点的结构就都统一到了二叉

表结构上了。这样有利于对结点进行操作。


2. 树的二叉链表(孩子-兄弟)存储

#include "ds.h"
typedef char TElemType;
TElemType Nil=' '; // 以空格符为空

typedef struct CSNode
{
	TElemType 	data;
	CSNode 		*firstchild, *nextsibling;
}CSNode, *CSTree;

#define 	ClearTree 		DestroyTree	// 二者操作相同

typedef 	CSTree 		QElemType;

typedef struct QNode{
	QElemType 		data;
	struct QNode 	*next;
}*QueuePtr;

struct LinkQueue{
	QueuePtr 	front, rear;
};

void InitQueue(LinkQueue &Q);
void DestroyQueue(LinkQueue &Q);
void ClearQueue(LinkQueue &Q);
Status QueueEmpty(LinkQueue Q);
void EnQueue(LinkQueue &Q, QElemType e);
Status DeQueue(LinkQueue &Q, QElemType &e);


// 带头结点的单链队列
void InitQueue(LinkQueue &Q)
{
	Q.front = (QueuePtr)malloc(sizeof(QNode));
	if (!Q.front) exit(OVERFLOW);
	
	Q.front->next = NULL;
	Q.rear = Q.front;
		
}
void DestroyQueue(LinkQueue &Q)
{
	QueuePtr q, p = Q.front;
	
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	
	Q.front = Q.rear = NULL;
}
void ClearQueue(LinkQueue &Q)
{
	QueuePtr q, p = Q.front->next;
	
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	Q.front->next = NULL;
	Q.rear = Q.front;
}
Status QueueEmpty(LinkQueue Q)
{
	if (Q.front == Q.rear)
		return TRUE;
	else
		return FALSE;
}


void EnQueue(LinkQueue &Q, QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p) exit(OVERFLOW);
	
	p->next = NULL;
	memcpy(&(p->data), &e, sizeof(QElemType));
	Q.rear->next = p;
	Q.rear = p;
}
Status DeQueue(LinkQueue &Q, QElemType &e)
{
	QueuePtr p = Q.front, q;
	if (Q.front == Q.rear)
		return FALSE;
	
	q = p->next;
	memcpy(&e, &(q->data), sizeof(QElemType));
	p->next = q->next;
	if (Q.rear == q)
		Q.rear = Q.front;
	free(q);
	
	return OK;
}




// 先根遍历孩子—兄弟二叉链表结构的树T
void PreOrderTraverse(CSTree T, void(*Visit)(TElemType))
{
	if (T)
	{
		Visit(T->data);	// 先访问根结点
		PreOrderTraverse(T->firstchild, Visit);		// 再先根遍历长子子树
		PreOrderTraverse(T->nextsibling, Visit);	// 最后先根遍历下一个兄弟子树
	}
}

void InitTree(CSTree &T)
{
	T = NULL;
}

void DestroyTree(CSTree &T)
{
	if (T)
	{
		if (T->firstchild)
			DestroyTree(T->firstchild);
		if (T->nextsibling)
			DestroyTree(T->nextsibling);
		free(T);
		T = NULL;
	}
}

void CreateTree(CSTree &T)
{
	char  		c[20];
	CSTree 		p, p1;
	LinkQueue	q;
	int 		i, l;
	InitQueue(q);
	
	printf("请输入根结点(字符型,空格为空): ");
	scanf("%c%*c", &c[0]);
	
	if (c[0] != Nil)	// 非空树
	{
		T = (CSTree)malloc(sizeof(CSNode));	// 建立根结点
		T->data = c[0];
		T->nextsibling = NULL;
		EnQueue(q, T);						// 入队根结点的指针
		
		while (!QueueEmpty(q))				// 队不空
		{
			DeQueue(q, p);					// 出队一个结点的指针
			printf("请按长幼顺序输入结点%c的所有孩子: ",p->data);
			gets(c);
			l = strlen(c);
			if (l > 0)						// 有孩子
			{
				p1 = p->firstchild = (CSTree)malloc(sizeof(CSNode));	// 建立长子结点
				p1->data = c[0];
				for (i = 1; i < l; i++)
				{
					p1->nextsibling = (CSTree)malloc(sizeof(CSNode));	// 建立下一个兄弟结点
					EnQueue(q, p1);			// 入队上一个结点
					p1 = p1->nextsibling;
					p1->data = c[i];
				}
				p1->nextsibling = NULL;
				EnQueue(q, p1);				// 入队最后一个结点
			}
			else
				p->firstchild = NULL;		// 长子指针为空
		}
	}
	else
     	T = NULL; // 空树
}

// 初始条件:树T存在。操作结果:若T为空树,则返回TURE,否则返回FALSE
Status TreeEmpty(CSTree T)
{ 
   	if(T) // T不空
     	return FALSE;
   	else
     	return TRUE;
 }
 
// 初始条件:树T存在。操作结果:返回T的深度
int TreeDepth(CSTree T)
{ 
   	CSTree p;
   	int depth, max = 0;
   	if (!T) // 树空
     	return 0;
   	if (!T->firstchild) // 树无长子
     	return 1;
   	for (p = T->firstchild; p; p = p->nextsibling)
   	{ // 求子树深度的最大值
     	depth = TreeDepth(p);
     	if (depth > max)
       		max = depth;
   	}
   	return max + 1; // 树的深度=子树深度最大值+1
}

// 返回p所指结点的值
TElemType Value(CSTree p)
{ 
   	return p->data;
}

// 初始条件:树T存在。操作结果:返回T的根
TElemType Root(CSTree T)
{ 
   	if(T)
     	return Value(T);
   	else
     	return Nil;
}

// 返回二叉链表(孩子—兄弟)树T中指向元素值为s的结点的指针。另加
CSTree Point(CSTree T,TElemType s)
{ 
   	LinkQueue q;
   	QElemType a;
   	if(T) // 非空树
   	{
     	InitQueue(q); // 初始化队列
     	EnQueue(q,T); // 根结点入队
     	while(!QueueEmpty(q)) // 队不空
     	{
       		DeQueue(q,a); // 出队,队列元素赋给a
       		if(a->data==s)
	 			return a;
       		if(a->firstchild) // 有长子
         		EnQueue(q,a->firstchild); // 入队长子
       		if(a->nextsibling) // 有下一个兄弟
         		EnQueue(q,a->nextsibling); // 入队下一个兄弟
     	}
   	}
   	return NULL;
}

// 初始条件:树T存在,cur_e是树T中结点的值。操作结果:改cur_e为value
Status Assign(CSTree &T,TElemType cur_e,TElemType value)
{ 
   	CSTree p;
   	if (T) // 非空树
   	{
     	p = Point(T, cur_e); // p为cur_e的指针
     	if (p) // 找到cur_e
     	{
       		p->data = value; // 赋新值
       		return OK;
     	}
   	}
   	return ERROR; // 树空或没找到
}

// 初始条件:树T存在,cur_e是T中某个结点
// 操作结果:若cur_e是T的非根结点,则返回它的双亲,否则函数值为"空"
TElemType Parent(CSTree T,TElemType cur_e)
{  
	CSTree p,t;
   	LinkQueue q;
   	InitQueue(q);
   	if(T) // 树非空
   	{
     	if (Value(T) == cur_e) // 根结点值为cur_e
       	return Nil;
     	EnQueue(q, T); // 根结点入队
     	while(!QueueEmpty(q))
     	{
       		DeQueue(q,p);
       		if(p->firstchild) // p有长子
       		{
         		if(p->firstchild->data==cur_e) // 长子为cur_e
           			return Value(p); // 返回双亲
         		t=p; // 双亲指针赋给t
         		p=p->firstchild; // p指向长子
         		EnQueue(q,p); // 入队长子
         		while(p->nextsibling) // 有下一个兄弟
	 			{
           			p=p->nextsibling; // p指向下一个兄弟
	   				if(Value(p)==cur_e) // 下一个兄弟为cur_e
             			return Value(t); // 返回双亲
           			EnQueue(q,p); // 入队下一个兄弟
         		}
       		}
     	}
   	}
   	return Nil; // 树空或没找到cur_e
}

// 初始条件:树T存在,cur_e是T中某个结点
// 操作结果:若cur_e是T的非叶子结点,则返回它的最左孩子,否则返回"空" 
TElemType LeftChild(CSTree T,TElemType cur_e)
{  
	CSTree f;
   	f = Point(T,cur_e); // f指向结点cur_e
   	if(f && f->firstchild) // 找到结点cur_e且结点cur_e有长子
     	return f->firstchild->data;
   	else
     	return Nil;
}

// 初始条件:树T存在,cur_e是T中某个结点
// 操作结果:若cur_e有右兄弟,则返回它的右兄弟,否则返回"空"
TElemType RightSibling(CSTree T,TElemType cur_e)
{  
	CSTree f;
   	f = Point(T,cur_e); // f指向结点cur_e
   	if(f && f->nextsibling) // 找到结点cur_e且结点cur_e有右兄弟
     	return f->nextsibling->data;
   	else
     	return Nil; // 树空
}

// 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度+1,非空树c与T不相交
// 操作结果:插入c为T中p结点的第i棵子树
// 因为p所指结点的地址不会改变,故p不需是引用类型
Status InsertChild(CSTree &T,CSTree p,int i,CSTree c)
{ 
   	int j;
   	if(T) // T不空
   	{
     	if(i==1) // 插入c为p的长子
     	{
       		c->nextsibling=p->firstchild; // p的原长子现是c的下一个兄弟(c本无兄弟)
       		p->firstchild=c;
     	}
     else // 找插入点
     {
       p=p->firstchild; // 指向p的长子
       j=2;
       while(p&&j<i)
       {
         p=p->nextsibling;
         j++;
       }
       if(j==i) // 找到插入位置
       {
         c->nextsibling=p->nextsibling;
         p->nextsibling=c;
       }
       else // p原有孩子数小于i-1
         return ERROR;
     }
     return OK;
   }
   else // T空
     	return ERROR;
}

// 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度
// 操作结果:删除T中p所指结点的第i棵子树
// 因为p所指结点的地址不会改变,故p不需是引用类型
Status DeleteChild(CSTree &T,CSTree p,int i)
{ 
   	CSTree b;
   	int j;
   	if(T) // T不空
   	{
    	if(i==1) // 删除长子
     	{
       		b=p->firstchild;
       		p->firstchild=b->nextsibling; // p的原次子现是长子
       		b->nextsibling=NULL;
       		DestroyTree(b);
     	}
     	else // 删除非长子
     	{
       		p=p->firstchild; // p指向长子
       		j=2;
       		while(p&&j<i)
       		{
         		p=p->nextsibling;
         		j++;
       		}
       		if(j==i) // 找到第i棵子树
       		{
         		b=p->nextsibling;
         		p->nextsibling=b->nextsibling;
         		b->nextsibling=NULL;
         		DestroyTree(b);
       		}
       		else // p原有孩子数小于i
         		return ERROR;
     	}
     	return OK;
   	}
   	else
     	return ERROR;
}

// 后根遍历孩子—兄弟二叉链表结构的树T
void PostOrderTraverse(CSTree T,void(*Visit)(TElemType))
{ 
   	CSTree p;
   	if(T)
   	{
     	if(T->firstchild) // 有长子
     	{
       		PostOrderTraverse(T->firstchild,Visit); // 后根遍历长子子树
       		p=T->firstchild->nextsibling; // p指向长子的下一个兄弟
       		while(p)
       		{
         		PostOrderTraverse(p,Visit); // 后根遍历下一个兄弟子树
         		p=p->nextsibling; // p指向再下一个兄弟
       		}
     	}
     	Visit(Value(T)); // 最后访问根结点
   	}
}

// 层序遍历孩子—兄弟二叉链表结构的树T
void LevelOrderTraverse(CSTree T,void(*Visit)(TElemType))
{ 
   	CSTree p;
   	LinkQueue q;
   	InitQueue(q);
   	if(T)
   	{
     	Visit(Value(T)); // 先访问根结点
     	EnQueue(q,T); // 入队根结点的指针
     	while(!QueueEmpty(q)) // 队不空
     	{
       		DeQueue(q,p); // 出队一个结点的指针
       		if(p->firstchild) // 有长子
       		{
         		p=p->firstchild;
         		Visit(Value(p)); // 访问长子结点
         		EnQueue(q,p); // 入队长子结点的指针
         		while(p->nextsibling) // 有下一个兄弟
         		{
           			p=p->nextsibling;
           			Visit(Value(p)); // 访问下一个兄弟
           			EnQueue(q,p); // 入队兄弟结点的指针
         		}
       		}
     	}
   	}
}

void vi(TElemType c)
{
   	printf("%c ",c);
}

int main()
{
   int i;
   CSTree T,p,q;
   TElemType e,e1;
   InitTree(T);
   printf("构造空树后,树空否? %d(1:是 0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));
   CreateTree(T);
   printf("构造树T后,树空否? %d(1:是 0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));
   printf("先根遍历树T:\n");
   PreOrderTraverse(T,vi);
   printf("\n请输入待修改的结点的值 新值: ");
   scanf("%c%*c%c%*c",&e,&e1);
   Assign(T,e,e1);
   printf("后根遍历修改后的树T:\n");
   PostOrderTraverse(T,vi);
   printf("\n%c的双亲是%c,长子是%c,下一个兄弟是%c\n",e1,Parent(T,e1),LeftChild(T,e1),RightSibling(T,e1));
   printf("建立树p:\n");
   InitTree(p);
   CreateTree(p);
   printf("层序遍历树p:\n");
   LevelOrderTraverse(p,vi);
   printf("\n将树p插到树T中,请输入T中p的双亲结点 子树序号: ");
   scanf("%c%d%*c",&e,&i);
   q=Point(T,e);
   InsertChild(T,q,i,p);
   printf("层序遍历树T:\n");
   LevelOrderTraverse(T,vi);
   printf("\n删除树T中结点e的第i棵子树,请输入e i: ");
   scanf("%c%d",&e,&i);
   q=Point(T,e);
   DeleteChild(T,q,i);
   printf("层序遍历树T:\n",e,i);
   LevelOrderTraverse(T,vi);
   printf("\n");
   DestroyTree(T);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值