您的位置:首页 > 理论基础 > 数据结构算法

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

2017-02-22 07:09 351 查看
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: