数据结构——键树之双链树


#include
"stdio.h"
#include
"stdlib.h"
#include
"string.h"

#define OK 1
#define ERROR 0
typedef
int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; // Boolean是布尔类型,其值是TRUE或false
#define N 16 // 数据元素个数
#define MAXKEYLEN 16 // 关键字的最大长度
#define Nil ' ' //定义结束符为空格
#define STACK_INIT_SIZE 10 // 存储空间初始分配量
#define STACKINCREMENT 2 // 存储空间分配增量

struct Others // 记录的其它部分
{
int ord;
};

struct KeysType // 关键字类型
{
char ch[MAXKEYLEN]; // 关键字
int num; // 关键字长度
};

struct Record // 记录类型
{
KeysType key;
// 关键字
Others others; // 其它部分(由主程定义)
};

enum NodeKind{LEAF,BRANCH}; // 结点种类:{叶子,分支}

typedef
struct DLTNode // 双链树类型
{
char symbol;
DLTNode
*next; // 指向兄弟结点的指针
NodeKind kind;
union
{
Record
*infoptr; // 叶子结点的记录指针
DLTNode *first; // 分支结点的孩子链指针
};
}DLTNode,
*DLTree;

struct SElemType // 定义栈元素类型
{
char ch;
DLTree p;
};
struct SqStack
{
SElemType
*base; // 在栈构造之前和销毁之后,base的值为NULL
SElemType *top; // 栈顶指针
int stacksize; // 当前已分配的存储空间,以元素为单位
}; // 顺序栈

Status InitDSTable(DLTree
&DT)
{
// 操作结果: 构造一个空的双链键树DT
DT=NULL;
return OK;
}
//InitDSTable

void DestroyDSTable(DLTree &DT)
{
// 初始条件: 双链键树DT存在。操作结果: 销毁双链键树DT
//我们采用深度优先来销毁。
if(DT) // 非空树
{
if(DT->kind==BRANCH&&DT->first) // *DT是分支结点且有孩子
DestroyDSTable(DT->first); // 销毁孩子子树
if(DT->next) // 有兄弟
DestroyDSTable(DT->next); // 销毁兄弟子树
free(DT); // 释放根结点
DT=NULL; // 空指针赋0
}
}
//DestroyDSTable

void print(Record e)
{
int i;
printf(
"(");
for(i=0;i<e.key.num;i++)
printf(
"%c",e.key.ch[i]);
printf(
",%d)",e.others.ord);
}
//print

Record
*SearchDLTree(DLTree T,KeysType K)
{
// 在非空双链键树T中查找关键字等于K的记录,若存在,
// 则返回指向该记录的指针,否则返回空指针。算法9.15,有改动
DLTree p;
int i;
if(T)
{
p
=T; // 初始化
i=0;
while(p&&i<K.num)
{
while(p&&p->symbol!=K.ch[i]) // 查找关键字的第i位
p=p->next;
if(p&&i<K.num) // 准备查找下一位
p=p->first;
++i;
}
// 查找结束

if(!p) // 查找不成功
return NULL;
else // 查找成功
return p->infoptr;
}
//if
else
return NULL; // 树空
}//SearchDLTree

void InsertDSTable(DLTree &DT,Record *r)
{
// 初始条件: 双链键树DT存在,r为待插入的数据元素的指针
// 操作结果: 若DT中不存在其关键字等于(*r).key.ch的数据元素,
// 则按关键字顺序插r到DT中
DLTree p=NULL,q,ap;
int i=0;
KeysType K
=r->key;
if(!DT && K.num) // 空树且关键字符串非空
{
DT
=ap=(DLTree)malloc(sizeof(DLTNode));
for(;i<K.num;i++) // 插入分支结点
{
if(p)
p
->first=ap;
ap
->next=NULL;
ap
->symbol=K.ch[i];
ap
->kind=BRANCH;
p
=ap;
ap
=(DLTree)malloc(sizeof(DLTNode));
}
//for

p
->first=ap; // 插入叶子结点
ap->next=NULL;
ap
->symbol=Nil;
ap
->kind=LEAF;
ap
->infoptr=r;//在叶子结点处记录指向该关键字的指针
}//if
else // 非空树
{
p
=DT; // 指向根结点
while(p&&i<K.num)
{
while(p&&p->symbol<K.ch[i]) // 沿兄弟结点查找
{
q
=p;
p
=p->next;
}
//while
if(p&&p->symbol==K.ch[i]) // 找到与K.ch[i]相符的结点
{
q
=p;
p
=p->first; // p指向将与K.ch[i+1]比较的结点
++i;
}
//if
else // 没找到,插入关键字
{
ap
=(DLTree)malloc(sizeof(DLTNode));
if(q->first==p)
q
->first=ap; // 在长子的位置插入
else // q->next==p;
q->next=ap; // 在兄弟的位置插入
ap->next=p;
ap
->symbol=K.ch[i];
ap
->kind=BRANCH;
p
=ap;
i
++;
ap
=(DLTree)malloc(sizeof(DLTNode));

for(;i<K.num;i++) // 插入分支结点
{
p
->first=ap;
ap
->next=NULL;
ap
->symbol=K.ch[i];
ap
->kind=BRANCH;
p
=ap;
ap
=(DLTree)malloc(sizeof(DLTNode));
}
//for

p
->first=ap; // 插入叶子结点
ap->next=NULL;
ap
->symbol=Nil;
ap
->kind=LEAF;
ap
->infoptr=r;
}
//else
}//while
}//else
}//InsertDSTable

//如下为对栈的操作
Status InitStack(SqStack &S)
{
// 构造一个空栈S
if(!(S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType))))
exit(
-1); // 存储分配失败
S.top=S.base;
S.stacksize
=STACK_INIT_SIZE;
return OK;
}

Status DestroyStack(SqStack
&S)
{
// 销毁栈S,S不再存在
free(S.base);
S.
base=NULL;
S.top
=NULL;
S.stacksize
=0;
return OK;
}

Status ClearStack(SqStack
&S)
{
// 把S置为空栈
S.top=S.base;
return OK;
}

Status StackisEmpty(SqStack S)
{
// 若栈S为空栈,则返回TRUE,否则返回false
if(S.top==S.base)
return true;
else
return false;
}

int StackLength(SqStack S)
{
// 返回S的元素个数,即栈的长度
return S.top-S.base;
}

Status GetTop(SqStack S,SElemType
&e)
{
// 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
if(S.top>S.base)
{
e
=*(S.top-1);
return OK;
}
else
return ERROR;
}

Status Push(SqStack
&S,SElemType e)
{
// 插入元素e为新的栈顶元素
if(S.top-S.base>=S.stacksize) // 栈满,追加存储空间
{
S.
base=(SElemType *)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));
if(!S.base)
exit(
-1); // 存储分配失败
S.top=S.base+S.stacksize;
S.stacksize
+=STACKINCREMENT;
}
*(S.top)++=e;
return OK;
}

Status Pop(SqStack
&S,SElemType &e)
{
// 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
if(S.top==S.base)
return ERROR;
e
=*--S.top;
return OK;
}

Status StackTraverse(SqStack S,Status(
*visit)(SElemType))
{
// 从栈底到栈顶依次对栈中每个元素调用函数visit()。
// 一旦visit()失败,则操作失败
while(S.top>S.base)
visit(
*S.base++);
printf(
"\n");
return OK;
}

void TraverseDSTable(DLTree DT,void(*Vi)(Record))
{
// 初始条件: 双链键树DT存在,Vi是对结点操作的应用函数,
// ViR是对记录操作的应用函数
// 操作结果: 按关键字的顺序输出关键字及其对应的记录
//我们用

SqStack s;
SElemType e;
DLTree p;
int i=0,n=8;
if(DT)
{
InitStack(s);
e.p
=DT;
e.ch
=DT->symbol;
Push(s,e);
//根结点入栈
p=DT->first;

while(p->kind==BRANCH) // 分支结点
{
e.p
=p;
e.ch
=p->symbol;
Push(s,e);
// 分支结点入栈
p=p->first;
}
//while

e.p
=p;
e.ch
=p->symbol; //Nil
Push(s,e);// 叶子结点入栈

Vi(
*(p->infoptr)); //print
i++;

while(!StackisEmpty(s))
{
//广度优先进行遍历
Pop(s,e);
p
=e.p;
if(p->next) // 有兄弟结点
{
p
=p->next;
while(p->kind==BRANCH) // 分支结点
{
e.p
=p;
e.ch
=p->symbol;
Push(s,e);
// 分支结点入栈
p=p->first;
}
//while
e.p=p;
e.ch
=p->symbol;

Push(s,e);
// 叶子结点入栈
Vi(*(p->infoptr));
i
++;

if(i%n==0)
printf(
"\n"); // 输出n个元素后换行
}//if
}//while
}//if(DT)
}//TraverseDSTable

void INputD(DLTree &t,Record r[])
{
Record
*p;
for(int i=0;i<N;i++)
{
r[i].key.num
=strlen(r[i].key.ch);
p
=SearchDLTree(t,r[i].key);
if(!p) // t中不存在关键字为r[i].key的项
InsertDSTable(t,&r[i]);
}
//for
}//INputD

void UserSearch(DLTree t)
{
char s[MAXKEYLEN+1];
Record
*p;
KeysType k;
printf(
"\n请输入待查找记录的关键字符串: ");
scanf(
"%s",s);
k.num
=strlen(s);
strcpy(k.ch,s);
p
=SearchDLTree(t,k);
if(p)
print(
*p);
else
printf(
"没找到");
printf(
"\n");
}
//UserSearch

int main()
{
DLTree t;
Record r[N]
={ {{"CAI"},1},{{"CAO"},2},{{"LI"},3},{{"LAN"},4},

{{
"CHA"},5},{{"CHANG"},6},{{"WEN"},7},{{"CHAO"},8},

{{
"YUN"},9},{{"YANG"},10},{{"LONG"},11},{{"WANG"},12},

{{
"ZHAO"},13},{{"LIU"},14},{{"WU"},15},{{"CHEN"},16} };

InitDSTable(t);
INputD(t,r);
printf(
"按关键字符串的顺序遍历双链键树:\n");
TraverseDSTable(t,print);
UserSearch(t);
DestroyDSTable(t);

return 1;
}

 

posted @ 2010-08-18 15:04  忧国忧铭  Views(974)  Comments(0Edit  收藏  举报