数据结构之树

本文详细探讨了数据结构中的树,包括树的基本概念、类型、操作及其实现。从二叉树到多叉树,从查找、插入到删除操作,深入解析树在算法和计算机科学中的应用。通过实例分析,揭示了树如何优化数据存储和检索效率,为软件开发提供高效解决方案。
摘要由CSDN通过智能技术生成

//对树的一些基本操作应按照处理森林的思想去理解,树是只有一棵树的森林
#include<iostream>
#include<malloc.h>
using namespace std;
#define QSIZE 20
typedef char ElemType;
typedef struct CSNode
{
	ElemType data;
	CSNode *pFchild;
	CSNode *pNsibling;
}CSNode, *CSTree;

typedef struct Queue
{
	CSTree *pBase;
	int Front;
	int Rear;
}Queue;

void InitQueue(Queue &Q)
{
	Q.pBase = new CSTree[QSIZE];
	Q.Front = 0;
	Q.Rear = 0;
}

void DestroyQueue(Queue &Q)
{
	delete[]Q.pBase;
	Q.Front = 0;
	Q.Rear = 0;
}

void ClearQueue(Queue &Q)
{
	Q.Front = 0;
	Q.Rear = 0;
}

bool QueueFull(Queue Q)
{
	if ((Q.Rear + 1) % QSIZE == Q.Front)
		return true;
	else
		return false;
}

bool QueueEmpty(Queue Q)
{
	if (Q.Front == Q.Rear)
		return true;
	else
		return false;
}

bool EnQueue(Queue &Q, CSTree e)
{
	if (QueueFull(Q))
		return false;
	else
	{
		Q.pBase[Q.Rear] = e;
		Q.Rear = (Q.Rear + 1) % QSIZE;
		return true;
	}
}

bool DeQueue(Queue &Q, CSTree &e)
{
	if (QueueEmpty(Q))
		return false;
	else
	{
		e = Q.pBase[Q.Front];
		Q.Front = (Q.Front + 1) % QSIZE;
		return true;
	}
}

bool GetHead(Queue Q, CSTree &e)
{
	if (QueueEmpty(Q))
		return false;
	else
	{
		e = Q.pBase[Q.Front];
		return true;
	}
}

#define STACKSIZE 10
#define SIZEADD 5
typedef CSTree SElemType;
typedef struct Stack
{
	SElemType *pBase;
	SElemType *pTop;
	int Stacksize;
}Stack;

void InitStack(Stack &S)
{
	S.pBase = new SElemType[STACKSIZE];
	S.pTop = S.pBase;
	S.Stacksize = STACKSIZE;
}

void DestroyStack(Stack &S)
{
	delete[]S.pBase;
	S.pBase = NULL;
	S.pTop = NULL;
	S.Stacksize = 0;
}

void ClearStack(Stack &S)
{
	S.pTop = S.pBase;
}

bool StackEmpty(Stack S)
{
	if (S.pBase == S.pTop)
		return true;
	else
		return false;
}

int StackLength(Stack S)
{
	return S.pTop - S.pBase;
}

void VisitS(SElemType e)
{
	cout << e->data << " ";
}

void Push(Stack &S, SElemType e)
{
	if (S.pTop - S.pBase >= S.Stacksize)
	{
		S.pBase = (SElemType *)realloc(S.pBase, (SIZEADD + STACKSIZE)*sizeof(SElemType));
		S.pTop = S.pBase + S.Stacksize;
		S.Stacksize += SIZEADD;
	}
	*S.pTop++ = e;
}

bool Pop(Stack &S)
{
	if (StackEmpty(S))
		return false;
	--S.pTop;
	return true;
}

bool GetTop(Stack S, SElemType &e)
{
	if (StackEmpty(S))
		return false;
	else
	{
		e = *(S.pTop - 1);
		return true;
	}
}

void StackDePrint(Stack S)
{
	SElemType *p = S.pTop;
	if (StackEmpty(S))
		return;
	while (p>S.pBase)
	{
		--p;
		VisitS(*p);
	}
	cout << endl;
}

void StackAsPrint(Stack S)
{
	SElemType *p = S.pBase;
	if (StackEmpty(S))
		return;
	while (p < S.pTop)
	{
		VisitS(*p);
		++p;
	}
	cout << endl;
}



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

void CreateTree(CSTree &T)
{
	ElemType array[20];
	CSTree p, p1;
	Queue Q;
	int i, l;
	InitQueue(Q);
	printf("请输入根结点(字符型,空格为空): ");
	cin >> array[0];
	if (array[0])// 非空树
	{
		T = new CSNode;// 建立根结点
		T->data = array[0];
		T->pNsibling = NULL;//只是一棵树
		EnQueue(Q, T);
		while (!QueueEmpty(Q))
		{
			DeQueue(Q, p);
			printf("请按长幼顺序输入结点%c的所有孩子: ", p->data);
			gets_s(array);
			l = strlen(array);
			if (l > 0)
			{
				p->pFchild = new CSNode; // 建立长子结点
				p1 = p->pFchild;
				p1->data = array[0];
				for (i = 1; i < l; ++i)
				{
					p1->pNsibling = new CSNode;// 建立下一个兄弟结点
					EnQueue(Q, p1);
					p1 = p1->pNsibling;
					p1->data = array[i];
				}
				p1->pNsibling = NULL;//最后一个兄弟
			}
			else
				p->pFchild = NULL;
		}
	}
	else
		T = NULL;
}

void DestroyTree(CSTree &T)
{
	if (T)
	{
		if (T->pFchild)
			DestroyTree(T->pFchild);
		if (T->pNsibling)
			DestroyTree(T->pNsibling);
		delete T;
		T = NULL;
	}
}

#define ClearTree DestroyTree

bool TreeEmpty(CSTree T)
{
	if (T)
		return false;
	else
		return true;
}

int TreeDepth(CSTree T)
{
	CSTree p;
	int depth, max = 0;
	if (!T)
		return 0;
	else if (!(T->pFchild))
		return 1;
	else
	{
		for (p = T->pFchild; p; p = p->pNsibling)
		{
			depth = TreeDepth(p);
			if (depth > max)
				max = depth;
		}
		return max + 1;
	}
}

ElemType Value(CSTree p)
{
	return p->data;
}

void VisitT(ElemType e)
{
	cout << e;
}

ElemType Root(CSTree T)
{
	if (T)
		return Value(T);
	else
		return NULL;
}

CSTree GetPoint(CSTree T, ElemType e)
{
	Queue Q;
	CSTree p;
	InitQueue(Q);
	if (T)
	{
		EnQueue(Q, T);
		while (!QueueEmpty(Q))
		{
			DeQueue(Q, p);
			if (p->data == e)
				return p;
			if (p->pFchild)
				EnQueue(Q, p->pFchild);
			if (p->pNsibling)
				EnQueue(Q, p->pNsibling);
		}
	}
	return NULL;
}

bool Assign(CSTree &T, ElemType cur, ElemType e)
{
	CSTree p;
	if (T)
	{
		p = GetPoint(T, cur);
		if (p)
		{
			p->data = e;
			return true;
		}
	}
	return false;
}

CSTree GetParent(CSTree T, ElemType e)
{
	CSTree p, t;
	Queue Q;
	InitQueue(Q);
	if (T)
	{
		if (Value(T) == e)//先处理根节点
			return NULL;
		EnQueue(Q, T);
		while (!QueueEmpty(Q))
		{
			DeQueue(Q, p);
			if (p->pFchild)
			{
				if (p->pFchild->data == e)//再处理根节点第一个孩子
					return p;
				t = p;
				p = p->pFchild;
				EnQueue(Q, p);
				while (p->pNsibling)//最后处理根节点的其他孩子(除长子)
				{
					p = p->pNsibling;
					if (Value(p) == e)
						return t;
					EnQueue(Q, p);
				}
			}
		}
	}
}

CSTree GetLeftChild(CSTree T, ElemType e)
{
	CSTree f;
	f = GetPoint(T, e);
	if (f && f->pFchild)
		return f->pFchild;
	else
		return NULL;
}

CSTree GetRightSibling(CSTree T, ElemType e)
{
	//只处理相邻的第一个兄弟
	CSTree f;
	f = GetPoint(T, e);
	if (f&&f->pNsibling)
		return f->pNsibling;
	else
		return NULL;
}

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

bool DeleteChild(CSTree &T, CSTree p, int i)
{ // 初始条件: 树T存在,p指向T中某个结点,1≤i≤p所指结点的度
	// 操作结果: 删除T中p所指结点的第i棵子树
	// 因为p所指结点的地址不会改变,故p不需是引用类型
	CSTree b;
	int j;
	if (T) // T不空
	{
		if (i == 1) // 删除长子
		{
			b = p->pFchild;
			p->pFchild = b->pNsibling; // p的原次子现是长子
			b->pNsibling = NULL;//断绝长子与次子的关系
			DestroyTree(b);
		}
		else // 删除非长子
		{
			p = p->pFchild; // p指向长子
			j = 2;
			while (p&&j<i)
			{
				p = p->pNsibling;
				++j;
			}
			if (j == i) // 找到第i棵子树
			{
				b = p->pNsibling;
				p->pNsibling = b->pNsibling;//p的右兄弟更新为b的右兄弟
				b->pNsibling = NULL;//断绝待删除孩子和紧挨该孩子的右兄弟的关系
				DestroyTree(b);
			}
			else // p原有孩子数小于i
				return false;
		}
		return true;
	}
	else
		return false;
}

void PreOrder(CSTree T)
{//树先根遍历(森林先序遍历)
	if (T)
	{//按照森林先序遍历思想理解
		VisitT(Value(T));
		PreOrder(T->pFchild);
		PreOrder(T->pNsibling);
	}
}

void PostOrderPrint(CSTree T)
{ // 后根遍历孩子-兄弟二叉链表结构的树T
	CSTree p;
	if (T)
	{
		if (T->pFchild)// 有长子
		{
			PostOrderPrint(T->pFchild);// 后根遍历长子子树(处理长子)
			p = T->pFchild->pNsibling; // p指向长子的下一个兄弟
			while (p)
			{//处理长子的所有兄弟也就是处理根除了长子之外的所有儿子
				PostOrderPrint(p);// 后根遍历下一个兄弟子树
				p = p->pNsibling;// p指向再下一个兄弟
			}
		}
		VisitT(Value(T)); // 最后访问根结点
	}
}

void LevelOrderPrint(CSTree T)
{// 层序遍历孩子-兄弟二叉链表结构的树T
	CSTree p;
	Queue Q;
	InitQueue(Q);
	if (T)
	{
		VisitT(Value(T));// 先访问根结点
		EnQueue(Q, T);// 入队根结点的指针
		while (!QueueEmpty(Q))// 队不空
		{
			DeQueue(Q, p); // 队头出队
			if (p->pFchild)// 有长子
			{
				p = p->pFchild;
				VisitT(Value(p));
				EnQueue(Q, p);
				while (p->pNsibling)//有下一个兄弟
				{
					p = p->pNsibling;
					VisitT(Value(p));// 访问下一个兄弟
					EnQueue(Q, p); // 入队兄弟结点的指针
				}
			}
		}
	}
}

void OutPathPrint(CSTree T, Stack &S)
{//森林思想
	while (!T)//每一次循环处理完一棵树;如果是树的话,只一次循环;如果是森林,有几棵树则循环几次
	{
		Push(S, T);//当前树的根结点入栈
		if (!T->pFchild)//如果当前结点无儿子,该结点必为叶子结点
			StackAsPrint(S);
		else
			OutPathPrint(T->pFchild, S);//对其长子结点进行递归处理
		Pop(S);//长子结点出栈
		T = T->pNsibling;//寻找下一个兄弟(如果是树的话,且第一循环则根结点的右指针域为空,整个函数处理完毕)
	}
}

int main(void)
{
	Stack S;
	CSTree T;
	InitStack(S);
	InitTree(T);
	CreateTree(T);
	LevelOrderPrint(T);
	OutPathPrint(T, S);
	return(0);
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值