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

  
    

#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 ;
}

 

你可能感兴趣的:(数据结构)