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

来源:互联网 发布:快速出效果图软件 编辑:程序博客网 时间:2024/06/07 19:57
#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;   }

原创粉丝点击