#include "stdio.h"#include "stdlib.h"#include "string.h"#define OK 1#define ERROR 0typedef 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 } }//DestroyDSTablevoid 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); }//printRecord *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) }//TraverseDSTablevoid 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}//INputDvoid 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");}//UserSearchint 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; }