数据结构之树和森林
提示:数据结构中树,森林的创建和二叉树的创建有着相似之处,都可以利用二叉树相关性质进行创建。
所以在本文章中我会重点对二叉树与树之间的差异点和共同点进行对比讲解,希望能给正在学习树的同学有一点帮助。
文章目录
一.树的基础知识点的讲解
树的基础知识点(在这里只介绍常见的孩子兄弟表示法)
观察发现
任意发现,任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针
分别指向该结点的第一个孩子和此节点的右兄弟。
及创建树的节点的结构为
typedef struct bintreenode
{
elemtype data;
bintreenode *firstchild,*nextsibling;
}bintreenode,*binlink;
这样可以树的结构转化为二叉树结构
因为在书中没有左右子树的概念,只有先根遍历和后根遍历的概念,与转化的二叉树的先序遍历和中序遍历相对应。
提示:以下是本篇文章正文内容,下面案例可供参考(本次代码实现中节点的data值的类型为字符串,所以在上篇文章的createbyedge中细节处做了改动)
二、代码实现
step1.头文件的引入
queue.h引入
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#include<string.h>
struct bintreenode;
#define qelemtype bintreenode*
typedef struct qnode
{
qelemtype data;
struct qnode *next;
}qnode,*qlink;
typedef struct
{
qlink front;
qlink rear;
}linkqueue;
void initqueue(linkqueue &q);
int isempty(linkqueue q);
void pushqueue(linkqueue &q,qelemtype e);
void popqueue(linkqueue &q,qelemtype &e);
void initqueue(linkqueue &q)
{
q.front=q.rear=(qlink)malloc(sizeof(qnode));
q.front->next=NULL;
}
void pushqueue(linkqueue &q,qelemtype e)
{
qlink p;
p=(qlink)malloc(sizeof(qnode));
p->data=e;
p->next=NULL;
q.rear->next=p;
q.rear=p;
}
void popqueue(linkqueue &q,qelemtype &e)
{
if(q.front==q.rear)
{
printf("队为空,没有可以删除的");
}
else
{
qlink p=q.front->next;
e=p->data;
q.front->next=p->next;
if(q.rear==p)
q.rear=q.front;
free(p);
}
}
int isempty(linkqueue q)
{
if(q.front==q.rear)
return 1;
else
return 0;
}
stack.h引入
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#define elemtype char
typedef struct bintreenode
{
elemtype data;
bintreenode *firstchild,*nextsibling;
}bintreenode,*binlink;
#define Elemtype bintreenode*
typedef struct snode {
Elemtype data;
struct snode* next;
}snode, * linkstack;
typedef struct snode_ {
Elemtype data;
struct snode_* next;
}snode_, * linkstack_;
void initstack(linkstack& s);
void pushstack(linkstack& s, Elemtype x);
void popstack(linkstack& s, Elemtype& x);
void pushstack_(linkstack_& s, Elemtype x);
void popstack_(linkstack_& s, Elemtype& x);
void printfstack(linkstack s);
int isempty(linkstack &s);
void initstack(linkstack& s)
{
s = (linkstack)malloc(sizeof(snode));
s->next = NULL;
//s = NULL;
}
void pushstack(linkstack& s, Elemtype x)
{
linkstack p = (linkstack)malloc(sizeof(snode));
p->data = x;
p->next = s;
s = p;
}
void pushstack_(linkstack_& s, Elemtype x)
{
linkstack_ p = (linkstack_)malloc(sizeof(snode_));
p->data = x;
p->next = s;
s = p;
}
void popstack(linkstack& s, Elemtype& x)
{
linkstack p = s;
x = p->data;
if(s->next==NULL)
{
s->next = NULL;
}
else {
s = s->next;
}
free(p);
}
void popstack_(linkstack_& s, Elemtype& x)
{
linkstack_ p = s;
x = p->data;
if (s->next == NULL)
{
s->next = NULL;
}
else {
s = s->next;
}
free(p);
}
int isempty(linkstack &s)
{
if(s->next==NULL)
{
return 1;
}
else
{
return 0;
}
}
void printfstack(linkstack s)
{
if(s->next!=NULL)
{
printfstack(s->next);
binlink bt=s->data;
printf("%c",bt->data);
}
}
step2.创建树结构
way1.先序字符串
void createbystr(forest *bt)
{
createbystr(bt->root);
}
void createbystr(binlink &t)
{
elemtype str[30];
scanf("%s",str);
initnode(t);
if(strcmp(str,"#")==0)
{
t=NULL;
}
else
{
strcpy(t->data,str);
createbystr(t->firstchild);
createbystr(t->nextsibling);
}
}
way2.边输边创建
void createbyedge(forest *bt)
{
createbyedge(bt->root);
}
void createbyedge(binlink &t)
{
initnode(t);
char f[30],s[30];
scanf("%s%s",f,s);
linkqueue q;
initqueue(q);
binlink bt,bc,bs;
initnode(bs);
if(strcmp(f,"#")==0)
{
strcpy(t->data,s);
pushqueue(q,t);
}
getchar();
scanf("%s%s",f,s);
while(!isempty(q))
{
popqueue(q,bt);
if(strcmp(bt->data,f)==0)
{
initnode(bc);
strcpy(bc->data,s);
bt->firstchild=bc;
pushqueue(q,bc);
getchar();
scanf("%s%s",f,s);
if(strcmp(s,"#")==0)
return;
while(strcmp(bt->data,f)==0)
{
strcpy(bs->data,s);
bc->nextsibling=bs;
pushqueue(q,bs);
getchar();
scanf("%s%s",f,s);
bc=bs;
initnode(bs);
}
}
}
}
step3.相应功能的实现
1.查找指定名称的节点
binlink find(forest *bt,elemtype *str)
{
return find(bt->root,str);
}
binlink find(binlink &t,elemtype *str)
{
if(t)
{
if(strcmp(t->data,str)==0)
return t;
binlink p=find(t->firstchild,str);
if(p)
return p;
else
return find(t->nextsibling,str);
}
else
return NULL;
}
2.查找指定名称的父节点
binlink findfather(forest *bt,elemtype *str)
{
binlink p=find(bt->root,str);
return findfather(bt->root,p);
}
binlink findfather(binlink &t,binlink p)
{
if(t==NULL||p==NULL||p==t)
return NULL;
binlink q=t->firstchild;
binlink parent;
while(q&&q!=p)
{
parent=findfather(q,p);
if(parent)
return parent;
q=q->nextsibling;
}
if(q==p)
return t;
return NULL;
}
3.输出所有叶子节点的路径
void output(forest *bt)
{
output(bt->root);
}
void output(binlink &t)
{
linkstack s;
initstack(s);
while(t)
{
pushstack(s,t);
t=t->firstchild;
if(!t)
{
printfstack(s);
popstack(s,t);
if(t->nextsibling)
t=t->nextsibling;
else
{
do
{
popstack(s,t);
}while(!t->nextsibling);
t=t->nextsibling;
}
}
}
}
4.删除指定名称的节点
void deletenode(forest *bt,elemtype *str)
{
binlink fnode=findfather(bt,str);
binlink cnode=find(bt,str);
deletenode(fnode,cnode);
}
void deletenode(binlink &fnode,binlink &cnode)
{
if(fnode->firstchild==cnode)
{
fnode->firstchild=NULL;
destroynode(cnode);
}
else
{
binlink bt=fnode->firstchild;
while(bt->nextsibling!=cnode)
bt=bt->nextsibling;
bt->nextsibling=NULL;
destroynode(cnode);
}
}
5.插入指定父节点的节点
void insert(forest *bt,elemtype *str1,elemtype *str2)
{
binlink fnode=find(bt->root,str1);
insert(fnode,str2);
}
void insert(binlink &fnode,elemtype *str)
{
binlink cnode,bt;
initnode(cnode);
strcpy(cnode->data,str);
if(!fnode->firstchild)
{
fnode->firstchild=cnode;
}
else
{
bt=fnode->firstchild;
while(bt->nextsibling)
bt=bt->nextsibling;
bt->nextsibling=cnode;
}
}
6.先序遍历树
void preorder(forest*bt)
{
preorder(bt->root);
}
void preorder(binlink &t)
{
if(t)
{
printf("%s",t->data);
printf(" ");
preorder(t->firstchild);
preorder(t->nextsibling);
}
}
树的应用赫尔曼编码我会放在下一个文章中单独写