1、中北大学数据结构与算法课程设计说 明 书学 院 、 系 : 软件学院专 业 : 软件工程班 级 : 1314010xxx学 生 姓 名:学 号:1314010xxx设 计 题 目 : 树的应用起 迄 日 期 : 2015 年 1 月 12 日- 2015 年 1 月 29 日指 导 教 师 : 尹四清2015 年 1 月 29 日1一、需求分析1.设计内容及设计要求A.设计内容:(1)建立一棵树;(2)将树转换成二叉树;(3)实现二叉树的前序、中序、后序的递归和非递归遍历算法。B.设计要求:(1) 符合课题要求,实现相应功能;(2) 要求界面友好美观,操作方便易行;(3) 注意程序的实用性、安
2、全性;2.本演示程序中,元素为单个字符,以空格表示空树(即结点为空),以回车符作为输入结束标志,树采用孩子兄弟表示法,二叉树采用二叉链表表示法。在真实的运行过程中,由用户手动输入待创建树的含有空格的先根次序序列,并按回车结束,程序会将其转化为其对应的二叉树,然后对二叉树进行先序、中序、后序的递归及非递归遍历以及层序遍历,然后显示转化后二叉树的高度和总结点数,以验证所创建的二叉树是否正确,最后,销毁创建的树和二叉树,程序结束。3.演示程序以用户和计算机对话方式执行,即在计算机终端(屏幕)上显示“提示信息”之后,由用户在键盘上输入演示程序规定的运算命令,相应的输入数据和运算结果显示在其后。4.为了
3、美观,程序的输出结果采用了分块显示的模式,由虚线及标题隔开,便于用户检查和验证。5.测试数据如图,给出一棵树,若屏幕上显示如下信息:-请按树的先根次序输入序列,如有空子树,用空格填充,完成后输入回车确认此时,你应当输入:(表示回车确认)ABE F C DGHI J K 提示:为方便确认输入了几个空格,用星号*表示输入序列中的空格,则序列如下ABE*F*C*DGHI*J*K*(不是真实的输入序列,供计算需输入空格个数时用)这时,建好的树的先根和后根次序序列如下:2树的先根序列 A B E F C D G H I J K树的后根序列 E F B C I J K H G D A由树和二叉树的转换关系
4、知,二叉树的先序和中序遍历所得序列分别与树的先根和后根遍历所得序列相同,据此验证转化是否正确。二叉树的先序和中序遍历序列如下:二叉树先序序列 A B E F C D G H I J K二叉树中序序列 E F B C I J K H G D A2、概要设计为了实现上述程序功能,树采用孩子兄弟表示法,二叉树采用二叉链表表示法。为此,需要两个抽象数据类型,树和二叉树的抽象数据类型。1.树的抽象数据类型定义ADT Tree 数据对象 D:D 是具有相同特性的数据元素的集合。 数据关系 R:若 D 为空集,则称为空树; 若 D 仅含有一个数据元素,则 R 为空集,否则 R=H,H 是如下二元关系: (1
5、)在 D 中存在唯一的称为根的数据元素 root,它在关系 H 下无前驱; (2)若 D-root,则存在 D-root的一个划分 D1,D2,D3, ,Dm(m0),对于任意 jk(1j,km)有 DjDk=,且对任意的 i(1im),唯一存在数据元素 xiDi 有H;(3)对应于 D-root的划分,H-,有唯一的一个划分H1,H2,Hm(m0),对任意 jk(1j,km)有 HjHk=,且对任意 i(1im),Hi 是 Di 上的二元关系,(Di,Hi)是一棵符合本定义的树,称为根 root 的子树。 基本操作 P: InitTree( 操作结果:构造空树 T。 DestroyTree(
6、 初始条件:树 T 存在。 操作结果:销毁树 T。 CreateTree( 初始条件:definition 给出树 T 的定义。 3操作结果:按 definition 构造树 T。 ClearTree( 初始条件:树 T 存在。 操作结果:将树 T 清为空树。 TreeEmpty(T); 初始条件:树 T 存在。 操作结果:若 T 为空树,则返回 TRUE,否则返回 FALSE。 TreeDepth(T); 初始条件:树 T 存在。 操作结果:返回的深度。 Root(T); 初始条件:树 T 存在。 操作结果:返回 T 的根。 Value(T,cur_e); 初始条件:树 T 存在,cur_e
7、 是 T 中某个结点。 操作结果:返回 cur_e 的值。 Assign(T,cur_e,value); 初始条件:树 T 存在,cur_e 是 T 中某个结点。 操作结果:结点 cur_e 赋值为 value。 Parent(T,cur_e); 初始条件:树 T 存在,cur_e 是 T 中某个结点。 操作结果:若 cur_e 是 T 的非根结点,则返回它的双亲,否则函数值为“空”。 LeftChild(T,cur_e); 初始条件:树 T 存在,cur_e 是 T 中某个结点。 操作结果:若 cur_e 是 T 的非叶子结点,则返回它的最左孩子,否则返回“空”。 RightSibling(
8、T,cur_e); 初始条件:树 T 存在,cur_e 是 T 中某个结点。 操作结果:若 cur_e 有右兄弟,则返回它的右兄弟,否则返回“空”。 InsertChild( 初始条件:树存在,指向中某个结点,1ip 指结点的度,非空树与4不相交。 操作结果:插入 c 为中指结点的第棵子树。 DeleteChild( 初始条件:树 T 存在,p 指向 T 中某个结点,1ip 指结点的度。 操作结果:删除中所指结点的第棵子树。 TraverseTree(T,visit(); 初始条件:树 T 存在,visit 是对结点操作的应用函数。 操作结果:按某种次序对 T 的每个结点调用函数 visit(
9、 )一次且至多一次。一旦visit( )失败,则操作失败。 ADT Tree2.二叉树的抽象数据类型定义ADT BinaryTree 数据对象 D:D 是具有相同特性的数据元素的集合。 数据关系 R: 若 D=,则 R=,称 BinaryTree 为空二叉树; 若 D,则 R=H,H 是如下二元关系; (1)在 D 中存在惟一的称为根的数据元素 root,它在关系 H 下无前驱; (2)若 D-root,则存在 D-root=D1,Dr,且 D1Dr =; (3)若 D1,则 D1 中存在惟一的元素 x1,H,且存在 D1 上的关系 H1 H;若 Dr,则 Dr 中存在惟一的元素 xr,H,且
10、存在上的关系 Hr H;H=,H1,Hr; (4)(D1,H1)是一棵符合本定义的二叉树,称为根的左子树;(Dr,Hr)是一棵符合本定义的二叉树,称为根的右子树。 基本操作: InitBiTree( /树中结点元素类型/-二叉树的二叉链表存储表示- typedef struct BiNodeTElemType data; /数据域,存储结点名称struct BiNode *lchild,*rchild; /孩子结点指针 BiNode,*BiTree;二叉树的二叉链表表示法示意图:/-树的孩子兄弟表示法- typedef struct CSNodeTElemType data; /数据域,存储结
11、点名称 struct CSNode *firstchild, *nextsibling; /孩子指针域和兄弟指针域 CSNode, *CSTree;树的孩子兄弟表示法示意图:92.构造一般树算法:按照树的先根次序序列构建一棵树:对于这棵树,按照需求分析第 1 页的测试数据,用户应当输入(表示回车确认)ABE F C DGHI J K 正确输入所需序列后,树的建立完成。Status CreateCSTree(CSTree ch=getchar();if(ch= )CT=NULL;elseif(!(CT=(CSNode *)malloc(sizeof(CSNode)printf(“内存分配失败!n
12、“);exit(OVERFLOW); /ifCT-data=ch; /生成根结点 CreateCSTree(CT-firstchild); /构建左子树 CreateCSTree(CT-nextsibling); /构建右子树 /else 10return OK; /CreateCSTree3.转换为二叉树 树和二叉树的转换关键在于树的二叉链表与其对应的二叉树的二叉链表是相同的,只是对同一个二叉链表的解释不同,二叉树的数据域存放结点名称,左指针域指向左孩子,右指针域指向右孩子;树的数据域存放结点名称,左指针域指向孩子结点,右指针域指向与该结点相邻的一个兄弟结点。当两者具有相同的存储结构时,便可
13、以完成转换,转换过程的实质是按照二叉树的定义将二叉链表解释为二叉树的过程。Status ExchangeToBiTree(CSTree else /若树的对应结点不空,申请内存空间if(!(T=(BiNode *)malloc(sizeof(BiNode) printf(“内存分配失败!n“);exit(OVERFLOW); /if/将树的数据域复制到二叉树对应的数据域T-data=CT-data; /若树的孩子域不为空,则用树的孩子域创建二叉树的左子树 ExchangeToBiTree(CT-firstchild,T-lchild); /若树的兄弟域不为空,则用树的兄弟域创建二叉树的右子树
14、ExchangeToBiTree(CT-nextsibling,T-rchild); /else 11/ExchangeToBiTree4.二叉树的遍历二叉树有先序、中序、后序、层序四种遍历方式,而先序、中序、后序遍历又有递归和非递归两种算法,总共有 7 个遍历算法。其中,先序、中序、后序非递归遍历算法需要用到栈,层序遍历需要使用队列,队列和栈的相关定义和算法请参考详细设计 P21。二叉树先序、中序、后序遍历的区别仅在于访问根结点的时机不同,而层序遍历则是逐层从左到右访问每一个结点。先序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则 访问根结点 (D); 先序遍历左子树 (L); 先序遍
15、历右子树 (R)。中序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则 中序遍历左子树 (L); 访问根结点 (D); 中序遍历右子树 (R)。后序遍历二叉树算法的框架是:若二叉树为空,则空操作;否则 后序遍历左子树 (L); 后序遍历右子树 (R); 访问根结点 (D)。虽然访问根结点的时机不同,但是先左后右的规则并没有改变。所有的遍历函数都调用元素访问函数 Visit,他们的参数列表中均含有一个函数指针变量Status(* Visit)(TElemType),通过主函数向他们传递元素访问函数 Visit 的函数名,就可以实现按元素访问函数 Visit 设定格式输出的目的。这样的好处在于
16、当输出格式改变时,只需修改元素访问函数 Visit 的输出格式而无需更改 7 个遍历函数,做到一改全改。以下是所有遍历算法的实现以及元素访问函数 Visit:/-元素访问函数 Visit- Status PrintElement(TElemType e) /输出元素 e 的值 printf(“ %c “,e); /元素类型设定为字符型return OK;/PrintElement/-递归算法- Status PreOrderTraverse(BiTree T,Status(* Visit)(TElemType) /先序遍历递归算法 12/采用二叉链表存储结构,Visit 是对数据元素操作的应用
17、函数/先序遍历二叉树 T 的递归算法,对每个数据元素调用函数 Visit if(T)if(Visit(T-data) /访问根结点if(PreOrderTraverse(T-lchild,Visit) /访问左子树if(PreOrderTraverse(T-rchild,Visit) /访问右子树return OK;return ERROR; /ifelse return OK;/PreOrderTraverseStatus InOrderTraverse(BiTree T,Status(* Visit)(TElemType) /中序遍历递归算法 /采用二叉链表存储结构,Visit 是对数据元
18、素操作的应用函数/中序遍历二叉树 T 的递归算法,对每个数据元素调用函数 Visit if(T)if(InOrderTraverse(T-lchild,Visit) /访问左子树if(Visit(T-data) /访问根结点if(InOrderTraverse(T-rchild,Visit) /访问右子树return OK;return ERROR; /ifelse return OK;/InOrderTraverse Status PostOrderTraverse(BiTree T,Status(* Visit)(TElemType) /后序遍历递归算法 /采用二叉链表存储结构,Visit
19、 是对数据元素操作的应用函数/后序遍历二叉树 T 的递归算法,对每个数据元素调用函数 Visit if(T)if(PostOrderTraverse(T-lchild,Visit) /访问左子树if(PostOrderTraverse(T-rchild,Visit) /访问右子树if(Visit(T-data) /访问根结点 13return OK;return ERROR;/ifelse return OK;/PostOrderTraverse/-非递归遍历算法-Status PreOrderTraverse1(BiTree T,Status(* Visit)(TElemType) /先序遍
20、历非递归算法 /采用二叉链表存储结构,Visit 是对数据元素操作的应用函数/先序遍历二叉树 T 的非递归算法,对每个数据元素调用函数 Visit Stack S;InitStack(S); /初始化栈BiTree p=T; /设置工作指针 p 并对其赋初值while(p|!(StackEmpty(S)if(p)if(!Visit(p-data) /访问根结点 return ERROR;Push(S,p); /根指针进栈 p=p-lchild; /遍历左子树/ifelsePop(S,p); /根指针退栈 p=p-rchild; /遍历右子树 /else/whilereturn OK; /Pre
21、OrderTraverse1Status InOrderTraverse1(BiTree T,Status(* Visit)(TElemType) /中序遍历非递归算法 /采用二叉链表存储结构,Visit 是对数据元素操作的应用函数/中序遍历二叉树 T 的非递归算法,对每个数据元素调用函数 Visit Stack S;14InitStack(S);BiTree p=T;while(p|!(StackEmpty(S)if(p)Push(S,p); /根指针进栈 p=p-lchild; /遍历左子树/ifelsePop(S,p); /根指针退栈 if(!Visit(p-data) /访问根结点 r
22、eturn ERROR;p=p-rchild; /遍历右子树 /else/whilereturn OK; /InOrderTraverse1Status PostOrderTraverse1(BiTree T,Status(* Visit)(TElemType) /后序遍历非递归算法 /采用二叉链表存储结构,Visit 是对数据元素操作的应用函数/后序遍历二叉树 T 的非递归算法,对每个数据元素调用函数 Visit BiTree p=T, q=NULL; / int n=0;Stack s;InitStack(s); while(p)|(!StackEmpty(s) while(p)Push(
23、s,p);p=p-lchild;/whileq=NULL;while(!StackEmpty(s)GetTop(s, p);15if(p-rchild=NULL)|(p-rchild=q)if(!Visit(p-data) /访问根结点 return ERROR; if(p=T) return ERROR;q=p;Pop(s,p);/ifelsep=p-rchild;break;/else/while/whilereturn OK; /PostOrderTraverse1Status LevelOrderTraverse1(BiTree T,Status(* Visit)(TElemType)
24、 /层序遍历非递归算法 /采用二叉链表存储结构,Visit 是对数据元素操作的应用函数/层序遍历二叉树 T 的算法,对每个数据元素调用函数 Visit Queue Q;BiTree p=T;if(T) /根结点入队列InitQueue(Q); /初始化队列 EnQueue(Q,T); while(!QueueEmpty(Q) /队列不空 DeQueue(Q,p);if(!Visit(p-data) /访问根结点 return ERROR;if(p-lchild)EnQueue(Q,p-lchild); /左孩子入队列 if(p-rchild)16EnQueue(Q,p-rchild); /右孩
25、子入队列 /whileprintf(“n“);/ifreturn OK; /LevelOrderTraverse15.二叉树的信息int BiTreeDepth(BiTree T) /递归求二叉树高度 /若二叉树 T 存在,返回 T 的深度(高度),否则返回 0int Thigh,leftThigh,rightThigh; /分别表示二叉树高度,左子树高度,右子树高度if(!T) return 0; /树高为 0elseleftThigh=BiTreeDepth(T-lchild); /求左子树高度 rightThigh=BiTreeDepth(T-rchild); /求右子树高度 if(le
26、ftThigh=rightThigh) /求二叉树高度 Thigh=leftThigh+1;elseThigh=rightThigh+1; /elsereturn Thigh;/BiTreeDepthint NodeSubNum(BiTree T) /统计二叉树的结点个数 if(!T) return 0; /二叉树为空树,没有结点 else return(NodeSubNum(T-lchild)+NodeSubNum(T-rchild)+1); /NodeSubNum6.销毁树 void DestoryCSTree(CSTree if(CT-nextsibling) /兄弟子树非空 Desto
27、ryCSTree(CT-nextsibling); free(CT); /释放根结点CT=NULL; /空指针赋 0 /if /DestoryTreevoid DestoryBiTree(BiTree if(T-rchild) /右子树非空,销毁右子树 DestoryBiTree(T-rchild); free(T); /释放根结点T=NULL; /空指针赋 0 /if /DestoryTreevoid DestoryTree(CSTree DestoryBiTree(T);printf(“-生成的树和二叉树已被销毁!“); /DestoryTree7.栈和队列的定义及算法/-栈的顺序存储表示
28、- typedef BiTree SElemType; /栈的元素为二叉树指针类型 typedef struct /栈的顺序存储表示 SElemType *base; /栈底指针,在栈构造之前和销毁之后,base 的值为NULL 18SElemType *top; /栈顶指针int stacksize; /当前已分配的存储空间,以元素为单位 Stack; /-队列的链式存储表示- typedef BiTree QElemType; /队列元素为二叉树指针类型typedef struct QNode /链队列的 C 语言表示 QElemType data; /数据域 struct QNode *
29、 next; /指针域 QNode,* QueuePtr;typedef structQueuePtr front; /队头指针 QueuePtr rear; /队尾指针 Queue; /-栈的相关函数(供非递归后序遍历使用)-Status InitStack(Stack exit(OVERFLOW); S.top=S.base;S.stacksize=STACK_INIT_SIZE;return OK; /InitStackStatus DestoryStack(Stack S.base=NULL;S.top=NULL; return OK; /DestoryStack19Status St
30、ackEmpty(Stack S)/判断顺序栈 S 是否为空栈,是返回 1,否返回 0 return S.top=S.base; /StackIsEmptyStatus Push(Stack exit(OVERFLOW); S.top = S.base + S.stacksize;S.stacksize +=STACKINCREMENT;*S.top+=e; /PushStatus Pop(Stack e=*-S.top; return OK; /PopStatus GetTop(Stack S,SElemType e = *(S.top-1); return OK; /GetTop/-队列的
31、相关函数(供非递归层序遍历使用)-QueuePtr MallocQNode()/为链队列结点申请内存的函数20QueuePtr p; /工作指针 p if(!(p=(QueuePtr)malloc(sizeof(QNode) /申请结点的内存空间,若失败则提示并退出程序printf(“内存分配失败,程序即将退出!n“);exit(OVERFLOW);return p; /MallocQNode Status InitQueue(Queue /申请头结点的内存空间,并使队头和队尾指针同时指向它 Q.front-next=NULL; Q.front-data=0; /将队长设为 0 return
32、OK;/InitQueueStatus DestoryQueue(Queue free(Q.front);Q.front=Q.rear; /whileprintf(“链队列已成功销毁!n“);return OK;/DestoryQueueStatus QueueEmpty(Queue Q) /若 Q 为空队列,则返回 OK;否则返回 ERRORif(Q.rear=Q.front) /队列为空的标志 return OK; return ERROR; /QueueEmpty21Status EnQueue(Queue p-data=e;p-next=NULL;Q.rear-next=p;Q.rea
33、r=p;Q.front-data+; /队长+1 return OK; /EnQueueStatus DeQueue(Queue QueuePtr p= Q.front-next;e = p-data;Q.front-next = p-next;if(Q.rear=p)Q.rear=Q.front;free(p);Q.front-data-; /队长-1 return OK; /DeQueue8.主函数int main(int argc,char *argv)printf(“- 树的应用 -n“);BiTree T=NULL; /声明一棵二叉树CSTree CT=NULL; /声明一棵普通树p
34、rintf(“ -树的建立- n“);printf(“-请按树的先根次序输入序列,如有空子树,用空格填充,完成后输入回车确认n“); 22CreateCSTree(CT);printf(“ -树的转换- n“);printf(“-正在将输入的树转换为其对应的二叉树.n“);ExchangeToBiTree(CT,T); printf(“-转换操作执行完毕!n“);printf(“n -二叉树的遍历- “);printf(“nn 先序遍历递归 算法结果:“); PreOrderTraverse(T,PrintElement);printf(“nn 中序遍历递归 算法结果:“); InOrderT
35、raverse(T,PrintElement);printf(“nn 后序遍历递归 算法结果:“); PostOrderTraverse(T,PrintElement); printf(“nn 先序遍历非递归算法结果:“); PreOrderTraverse1(T,PrintElement);printf(“nn 中序遍历非递归算法结果:“); InOrderTraverse1(T,PrintElement);printf(“nn 后序遍历非递归算法结果:“); PostOrderTraverse1(T,PrintElement);printf(“nn 层序遍历非递归算法结果:“); Leve
36、lOrderTraverse1(T,PrintElement); printf(“n -二叉树的信息- “);printf(“n 该二叉树的高度:%d“,BiTreeDepth(T); printf(“n 二叉树总结点数:%d“,NodeSubNum(T) );printf(“nn - 树的销毁 - “);DestoryTree(CT,T); printf(“n-算法演示结束!“); system(“pause“); return 0;/main主函数与其他函数的关系234、调试与分析1.之前编写的栈和队列存在一个问题,当时调试没有发现,但是在本次编写二叉树后序非递归遍历函数调试时出现了错误,
37、经过仔细检查,发现插入函数出现了错误。顺序栈的插入需要判断栈是否满而无需判断栈是否空,链队列入队既不需要判断满,也不需要判断空。之前编写的栈和队列我忽视了这一点,机械的在每一个栈和队列的插入删除等实际操作函数中都加入了判断空的语句,使得栈和队列空时无法再执行插入操作,导致了遍历的结果异常。今后要注意这一问题。2.本程序的模块划分比较合理,将栈和队列的相关操作封装在相应的模块中,使得后序遍历非递归算法的模块调试比较顺利,比较容易调试,反之,如果出现问题,很难确定是遍历算法本身还是栈和队列谁出了问题,调试会比较困难。3.算法的时空分析遍历二叉树的基本操作是访问结点,则不论按照哪一种次序进行遍历,对
38、于含有 n 个结点的二叉树,其时间复杂度为 O(n),所需辅助空间为栈的最大容量,即树的深度,最坏情况下为 n,则空间复杂度为 O(n)。同理,树的创建,树的转换,树和二叉树的销毁时间复杂度均为 O(n)。4.本次课程设计采用了数据抽象的程序设计方法和结构化的程序设计方法,将程序划分为五个模块,使程序设计时思路清晰,实现时调试顺利,各模块具有较好的可重用性,确实得到了一次良好的程序设计训练。24五、用户手册。1.本程序的运行环境为 Windows 7 64 bit 中文旗舰版操作系统命令提示符 cmd,执行文件为CSTree.exe。2.进入演示程序后显示文本方式的中文用户界面。3.用户手动输
39、入树的先根次序序列,空子树用空格表示:(表示回车确认)如:ABE F C DGHI J K 输入完成后,程序会自动建立树。4.程序会自动完成相关操作,结果会显示在屏幕上。256、测试结果运行程序,输入:ABE F C DGHI J K 查看运行结果,如图所示:267、心得体会1. 在计算机科学中,许多数据结构(如广义表、树、二叉树等)都是通过递归方式加以定义的,具有固有的递归性质,处理算法可采用递归技术。递归算法程序的优点在于结构清晰、可读性强、便于理解、容易证明等。但递归程序在执行过程中,伴随着函数自身的多次调用,因27此其执行效率较低。要使用递归技术进行程序设计,首先必须将要求解的问题分解
40、成若干个子问题,这些子问题的结构与原问题的结构相同,但规模较原问题小。由于子问题与原问题结构相同,因而它们的求解过程相同,在程序设计时不必再仔细考虑子问题的求解过程,只需借助递归机制进行函数自身调用加以实现,然后利用所得到的子问题的解组合成原问题的解即可。而递归程序在执行过程中,通过不断修改参数进行自身调用,将子问题分解为更小的子问题进行求解,直到最终分解成的子问题可以直接求解为止。因此,递归程序设计时必须要有一个终止条件,当程序的执行使终止条件得到满足时,递归过程便结束;否则,递归将会无休止地进行下去,导致程序的执行无法正常终止。本次程序除了二叉树的先序、中序、后序非递归算法和层序遍历以及栈
41、和队列的算法,其余算法均为递归算法。设计过程中确实感觉到了递归算法的易于设计,算法简洁,便于理解等优点。2.程序设计的过程中碰到困难是很正常的,遇到错误时,要耐心调试,借助各种手段找到错误的真正原因并且加以解决,程序设计的能力才会提高。八、参考书目1 李云清,杨庆红 .数据结构(C 语言版).北京:人民邮电出版社,2004.2 严蔚敏,吴伟民 .数据结构(C 语言版).北京:清华大学出版.1997.3 严蔚敏,吴伟民,米宁.数据结构题集(C 语言版).北京:清华大学出版.1997.4 苏光奎,李春葆 .数据结构导学.北京:清华大学出版.2002. 5 周海英,马巧梅,靳雁霞.数据结构与算法设计.北京:国防工业出版社,2007.6 张海藩. 软件工程导论. 北京:清华大学出版社.2003.7 滕国文. 数据结构课程设计 北京:清华大学出版社.2010.8 高一凡. 数据结构算法实现与解析 西安交通大学出版社.2002.9 (美)Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein 著;殷建平,徐云,王刚 等译. 算法导论 机械工业出版社.2013.