人人范文网 教学计划

数据结构 教学计划(精选多篇)

发布时间:2021-01-12 08:33:37 来源:教学计划 收藏本文 下载本文 手机版

推荐第1篇:数据结构

实验:线性表的基本操作

【实验目的】

学习掌握线性表的顺序存储结构、链式存储结构的设计与操作。对顺序表建立、插入、删除的基本操作,对单链表建立、插入、删除的基本操作算法。

【实验内容】

1.顺序表的实践

1) 建立4个元素的顺序表s=sqlist[]={1,2,3,4,5},实现顺序表建立的基本操作。

2) 在sqlist []={1,2,3,4,5}的元素4和5之间插入一个元素9,实现顺序表插入的基本操作。

3) 在sqlist []={1,2,3,4,9,5}中删除指定位置(i=5)上的元素9,实现顺序表的删除的基本操作。 2.单链表的实践

3.1) 建立一个包括头结点和4个结点的(5,4,2,1)的单链表,实现单链表建立的基本操作。

2) 将该单链表的所有元素显示出来。

3) 在已建好的单链表中的指定位置(i=3)插入一个结点3,实现单链表插入的基本操作。

4) 在一个包括头结点和5个结点的(5,4,3,2,1)的单链表的指定位置(如i=2)删除一个结点,实现单链表删除的基本操作。 5) 实现单链表的求表长操作。

【实验步骤】

1.打开VC++。

2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。

3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了你刚创建的工程之中。

4.写好代码

5.编译->链接->调试

【实验心得】

线性是我们学习数据结构中,碰到的第一个数据结构。学习线性表的重点掌握顺序表和单链表的各种算法和时间性能分析。线性表右两种存储方式即顺序存储结构和链式存储结构。通过学习我知道了对线性表进行建立、插入、删除,同时单链表也是进行建立、插入、删除。而对于顺序表的插入删除运算,其平均时间复杂度均为0(n).通过这次的学习,掌握的太熟练,主要是课本上的知识点没有彻底的理解,回去我会多看书,理解重要的概念。总之,这次实验我找到了自己的不足之处,以后会努力的。

实验二:栈的表示与实现及栈的应用

【实验目的】

(1) 掌握栈的顺序存储结构及其基本操作的实现。 (2) 掌握栈后进先出的特点,并利用其特性在解决实际问题中的应用。 (3) 掌握用递归算法来解决一些问题。 【实验内容】

1.编写程序,对于输入的任意一个非负十进制整数,输出与其等值的八进制数。

2.编写递归程序,实现N!的求解。3.编写递归程序,实现以下函数的求解。

n,n0,1Fib(n) Fib(n1)Fib(n2),n1

4.编写程序,实现Hanoi塔问题。【实验步骤】 1.打开VC++。

2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。

3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了你刚创建的工程之中。

4.写好代码

5.编译->链接->调试

【实验心得】

通过这次的学习我掌握了栈这种抽象数据类型的特点,并能在相应的应用任务中正确选用它;总的来说,栈是操作受限的线性表,是限定仅在表尾进行插入或删除操作的线性表。因此,对栈来说,表尾端有其特殊含义,称为栈顶(top),相应地,表头端称为栈底(botton);栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构,因为它的修改是按后进先出的原则进行的。

加上这个实验,我已经学了线性表(顺序表,单链表)和栈,知道它们都是线性表,而且对以后的学习有很大的作用,可以说这是学习以后知识的总要基础。

实验三:二叉树的建立及遍历

【实验目的】

(1) 掌握利用先序序列建立二叉树的二叉链表的过程。 (2) 掌握二叉树的先序、中序和后序遍历算法。 【实验内容】

1.编写程序,实现二叉树的建立,并实现先序、中序和后序遍历。如:输入先序序列abc###de###,则建立如下图所示的二叉树。

并显示其先序序列为:abcde 中序序列为:cbaed 后序序列为:cbeda 【实验步骤】 1.打开VC++。

2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。

3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了你刚创建的工程之中。

4.写好代码

5.编译->链接->调试

【实验心得】

这次试验是关于二叉树的常见操作,主要是二叉树的建立和遍历,在这次实验中我按先序方式建立二叉树的,而遍历方式则相对要多一些,有递归的先序、中序、后序遍历,和非递归的先序、中序、后序遍历,此外还有层次遍历.二叉树高度和叶子个数的计算和遍历相差不大,只是加些判断条件,总体来说,本次试验不太好做,期间出现了很多逻辑错误,变量初始化的问题等,不过经过仔细排查最后都一一解决了。

实验四:查找与排序

【实验目的】

(1) 掌握折半查找算法的实现。 (2) 掌握冒泡排序算法的实现。 【实验内容】

1.编写折半查找程序,对以下数据查找37所在的位置。5,13,19,21,37,56,64,75,80,88,92 2.编写冒泡排序程序,对以下数据进行排序。 49,38,65,97,76,13,27,49 【实验步骤】 1.打开VC++。

2.建立工程:点File->New,选Project标签,在列表中选Win32 Console Application,再在右边的框里为工程起好名字,选好路径,点OK->finish。至此工程建立完毕。

3.创建源文件或头文件:点File->New,选File标签,在列表里选C++ Source File。给文件起好名字,选好路径,点OK。至此一个源文件就被添加到了你刚创建的工程之中。

4.写好代码

5.编译->链接->调试

(1)查找算法的代码如下所示: #include \"stdio.h\" #include \"malloc.h\" #define OVERFLOW -1 #define OK 1 #define MAXNUM 100 #define N 10 typedef int Elemtype; typedef int Status; typedef struct {

Elemtype *elem;

int length; }SSTable; Status InitList(SSTable &ST ) { int i,n;

ST.elem =

(Elemtype*)

malloc (Elemtype));

if (!ST.elem) return(OVERFLOW);

printf(\"输入元素个数和各元素的值:\");

scanf(\"%d\\n\",&n);

for(i=1;i

(MAXNUM*sizeof

scanf(\"%d\",&ST.elem[i]); }

ST.length = n;

return OK; } int Seq_Search(SSTable ST,Elemtype key) {

int i;

ST.elem[0]=key;

for(i=ST.length;ST.elem[i]!=key;--i);

return i; } int BinarySearch(SSTable ST,Elemtype key) {

int mid,low,high,i=1;

low=1;

high=ST.length;

while(low

{

mid=(low+high)/2;

if(ST.elem[mid]==key)

return mid;

else if(key

high=mid-1;

else

}

return 0; } void main() { SSTable ST; InitList(ST);

Elemtype key; int n; printf(\" key= \");

scanf(\"%d\",&key);

printf(\"\\n\\n\");

/*printf(\"After SeqSearch:: \");

n=Seq_Search(ST,key);

printf(\"position is in %d \\n\\n\",n);*/

printf(\"After Binary Search::\");

n=BinarySearch(ST,key);

low=mid+1; if(n) printf(\"position is in %d \\n\\n\",n); else

} 实验结果如下所示:

(2)排序算法的代码如下所示: #include \"stdio.h\" #include \"malloc.h\" #define OVERFLOW -1 #define OK 1 #define MAXNUM 100 #define N 10 typedef int Elemtype; typedef int Status; typedef struct {

Elemtype *elem;

int length; }SSTable; Status InitList(SSTable &ST ) printf(\"not in \\n\\n\"); { int i,n;

ST.elem (Elemtype));

if (!ST.elem) return(OVERFLOW);

printf(\"输入元素个数和各元素的值:\");

scanf(\"%d\\n\",&n);

for(i=1;i

scanf(\"%d\",&ST.elem[i]); }

ST.length = n;

return OK; } void Sort(SSTable ST) {

int i,j,t;

for(i=1;i

for(j=i+1;j

if(ST.elem[i]>ST.elem[j]) { t=ST.elem[i]; =

(Elemtype*)

malloc

(MAXNUM*sizeof

}

} ST.elem[i]=ST.elem[j]; ST.elem[j]=t; void display(SSTable ST) { int i;

for(i=1;i

printf(\"%d

\",ST.elem[i]); }

} void main() {

SSTable ST; InitList(ST); int n; printf(\"before sort::\\n\"); display(ST); Sort(ST); printf(\"\\nafter sort::\\n\"); display(ST); } 实验结果如下所示:

【实验心得】

通过这次实验,我明白了程序里的折半查找和冒泡查找.其实排序可以有很多种,但是其目的应该都是为了能够在海量的数据里迅速查找到你要的数据信息,折半查找是种比较快的方式,但前提是要是有 序的排序才可以。对于有序表,查找时先取表中间位置的记录关键字和所给关键字进行比较,若相等,则查找成功;如果给定值比该记录关键字大,则在后半部分继续进行折半查找;否则在前半部分进行折半查找,直到查找范围为空而查不到为止。折半查找的过程实际上死先确定待查找元素所在的区域,然后逐步缩小区域,直到查找成功或失败为止。算法中需要用到三个变量,low表示区域下界,high表示上界,中间位置mid=(low+high)/2.而冒泡查找则是从小到大的排序.

推荐第2篇:数据结构

数据结构】二叉排序树的建立,查找,插入和删除实践题 /*sy53.c*/

#include

#include

typedef int KeyType;

typedef struct node{

KeyType key;

struct node *lchild,*rchild;

}BSTNode;

typedef BSTNode *BSTree;

BSTree CreateBST(void);

void SearchBST(BSTree T,KeyType Key);

void InsertBST(BSTree *Tptr,KeyType Key);

void DelBSTNode(BSTree *Tptr,KeyType Key);

void InorderBST(BSTree T);

main()

{BSTree T;

char ch1,ch2;

KeyType Key;

printf(\"建立一棵二叉排序树的二叉链表存储\\n\");

T=CreateBST();

ch1=\'y\';

while (ch1==\'y\' || ch1==\'Y\')

{printf(\"请选择下列操作:\\n\");

printf(\"1------------------更新二叉排序树存储\\n\");

printf(\"2------------------二叉排序树上的查找\\n\");

printf(\"3------------------二叉排序树上的插入\\n\");

printf(\"4------------------二叉排序树上的删除\\n\");

printf(\"5------------------二叉排序树中序输出\\n\");

printf(\"6------------------退出\\n\");

scanf(\"\\n%c\",&ch2);

switch (ch2)

{case \'1\':T=CreateBST();break;

case \'2\':printf(\"\\n请输入要查找的数据:\");

scanf(\"\\n%d\",&Key);

SearchBST(T,Key);

printf(\"查找操作完毕。\\n\");break;

case \'3\': printf(\"\\n请输入要插入的数据:\");

scanf(\"\\n%d\",&Key);

InsertBST(&T,Key);

printf(\"插入操作完毕。\\n\");break;

case \'4\': printf(\"\\n请输入要删除的数据:\");

scanf(\"\\n%d\",&Key);

DelBSTNode(&T,Key);

printf(\"删除操作完毕。\\n\");break;

case \'5\': InorderBST(T);

printf(\"\\n二叉排序树输出完毕。\\n\");break;

case \'6\':ch1=\'n\';break;

default:ch1=\'n\';

}

}

}

BSTree CreateBST(void)

{BSTree T;

KeyType Key;

T=NULL;

printf(\"请输入一个关键字(输入0时结束输入):\\n\"); scanf(\"%d\",&Key);

while (Key)

{InsertBST(&T,Key);

printf(\"请输入下一个关键字(输入0时结束输入):\\n\"); scanf(\"\\n%d\",&Key);

}

return T;

}

void SearchBST(BSTree T, KeyType Key)

{ BSTNode *p=T;

while(p)

{if(p->key==Key)

{printf(\"已找到\\n\");

return;

}

p=(Keykey) ? p->lchild:p->rchild;

}

printf(\"没有找到\\n\");

}

void InsertBST(BSTree *T,KeyType Key)

{BSTNode *f,*p;

p=(*T);

while(p)

{if(p->key==Key)

{printf(\"树中已有Key不需插入\\n\");

return;

}

f=p;

p=(Keykey)?p->lchild:p->rchild;

}

p=(BSTNode*)malloc(sizeof(BSTNode));

p->key=Key;

p->lchild=p->rchild=NULL;

if ((*T)==NULL) (*T)=p;

else if (Keykey) f->lchild=p;

else f->rchild=p;

}/*InsertBST*/

void DelBSTNode(BSTree *T,KeyType Key)

{BSTNode *parent=NULL, *p, *q,*child;

p=*T;

while(p)

{if(p->key==Key) break;

parent=p;

p=(Keykey)?p->lchild:p->rchild;

}

if (!p) {printf(\"没有找到要删除的结点\\n\");return;}

q=p;

if (q->lchild && q->rchild)

for (parent=q,p=q->rchild; p->lchild; parent=p,p=p->lchild); child=(p->lchild)?p->lchild:p->rchild;

if (!parent) *T=child;

else {if (p==parent->lchild)

parent->lchild=child;

else parent->rchild=child;

if (p!=q)

q->key=p->key;

}

free(p);

}

void InorderBST(BSTree T) { if(T!=NULL)

{InorderBST(T->lchild); printf(\"%5d\",T->key); InorderBST(T->rchild); }

}

推荐第3篇:数据结构讲稿

云淡风清 http://gsqls.blog.163.com/

第1章 数据结构概述

1.1概述

以下为某市部分院校的交通地图情况,要求找出从出发点到目的地之间的最短路径及其长度。

对于此问题,如果手工去做,速度慢(特别地,现实中实际地图信息要比此例复杂许多),还容易出错,此时可借助于计算机完成。

计算机进行此类信息的处理时,涉及到两个问题:一是现实当中的信息在计算机中如何表示,二是如何对信息进行处理。

信息的表示和组织又直接关系到处理信息的程序的效率。随着应用问题不断复杂化,导致信息量剧增与信息范围的拓宽,使许多系统程序和应用程序的规模很大,结构又相当复杂。因此,必须分析待处理问题中的对象的特征及各对象之间存在的关系,这就是数据结构这门课所要研究的问题。

1.1.1编写解决实际问题的程序的一般流程

如何通过编写程序,以比手工更为高效精确的方式解决实际问题呢?一般流程如下:

1、由具体问题抽象出一个适当的数学模型;

2、分析问题所涉及的数据量大小及数据之间的关系;

3、确定如何在计算机中存储数据及体现数据之间的关系?

4、确定处理问题时需要对数据作何种运算?

5、确定算法并编写程序;

5、分析所编写的程序的性能是否良好?若性能不够好则重复以上步骤。

云淡风清 http://gsqls.blog.163.com/ 上面所列举的问题基本上由数据结构这门课程来回答。

《数据结构》是计算机科学中的一门综合性专业基础课,是介于数学、计算机硬件、计算机软件三者之间的一门核心课程,不仅是一般程序设计的基础,而且是设计和实现编译程序、操作系统、数据库系统及其他系统程序和大型应用程序的重要基础。

1.1.2数据结构的例子

1、电话号码查询系统

设有一个电话号码薄,它记录了N个人的名字和其相应的电话号码。要求设计一个算法,当给定任何一个人的名字时,该算法能够打印出此人的电话号码,如果该电话簿中根本就没有这个人,则该算法也能够报告没有这个人的标志。

姓名

电话号码

陈伟海 13612345588 李四锋 13056112345 。。。

这是一种典型的线性结构。

2、磁盘目录文件系统

磁盘根目录下有很多子目录及文件,每个子目录里又可以包含多个子目录及文件,但每个子目录只有一个父目录,依此类推。

。。。

本问题中各目录从上到小形成了一种一对多的关系,是一种典型的树形结构。

云淡风清 http://gsqls.blog.163.com/

3、交通网络图

下图表明了若干个城市之间的联系:

从图中可看出,一个地方到另外一个地方可以有多条路径,是一种典型的网状结构,数据与数据成多对多的关系。

4、排序问题

对100000个整数进行降序排序。 冒泡法程序: #include #include #include #define N 100000 void main() { int i,j; int a[N+1]; srand(time(NULL)); for(i=1;i

a[i]=rand(); printf("\n按原序输出:\n"); for(i=1;i

printf("%8d",a[i]); system("pause"); for(j=1;j

for(i=N;i>j;i--)

if(a[i]>a[i-1])

{

a[0]=a[i];

a[i]=a[i-1];

a[i-1]=a[0];

} printf("\n按新次序输出:\n");

云淡风清 http://gsqls.blog.163.com/ for(i=1;i

printf("%8d",a[i]); printf("\n"); } 快速排序程序: #include #include #include #define N 100000

void quick_sort(int a[N+1],int left,int right) { int j,last,temp; if(left

{

//将划分子集的元素(此处选中间元素)移动到最左边

temp=a[left];

a[left]=a[(left+right)/2];

a[(left+right)/2]=a[left];

last=left;//用last记录比关键字小的元素的最右位置

for(j=left+1;j

if(a[j]>a[left])

{

temp=a[last];

a[last]=a[j];

a[j]=temp;

last++;

}

//对形成的新子集递归进行快速排序

quick_sort(a,left,last-1);

quick_sort(a,last+1,right); } } void main() { int i; int a[N+1]; srand(time(NULL)); for(i=1;i

a[i]=rand(); printf("\n按原序输出:\n"); for(i=1;i

printf("%8d",a[i]); system("pause");

云淡风清 http://gsqls.blog.163.com/ quick_sort(a,1,N); printf("\n按新次序输出:\n"); for(i=1;i

printf("%8d",a[i]); printf("\n"); } 运行可知,两者速度差异非常明显,主要是排序所花的时间差别很大。可看出,同样的问题,采用不同方法进行处理,有可能呈现出非常大的性能方面的差异。

还可以找到许多其它例子,如图书馆的书目检索系统自动化问题,教师资料档案管理系统,多叉路口交通灯的管理问题等。

1.2基本概念和术语 1.2.1数据(Data):

是客观事物的符号表示。在计算机科学中指的是所有能输入到计算机中并被计算机程序处理的符号的总称。

1.2.2数据元素(Data Element):

是数据的基本单位,在程序中通常作为一个整体来进行考虑和处理。一个数据元素可由若干个数据项(Data Item)组成。数据项是数据的不可分割的最小单位。数据项是对客观事物某一方面特性的数据描述。

1.2.3数据对象(Data Object):

是性质相同的数据元素的集合,是数据的一个子集,其中的数据元素可以是有限的,也可以是无限的。如整数集合:N={0,±1,±2,…},是无限集,而字符集合:C={ˊAˊ,Bˊ,…,ˊZˊ}则为有限集。

1.2.4数据的逻辑结构:

指对数据元素之间逻辑关系的描述。

数据元素之间的关系可以是一种或多种。

数据元素之间的关系可以是元素之间代表某种含义的自然关系,也可以是为处理问题方便而人为定义的关系,这种自然或人为定义的“关系”称为数据元素之间的逻辑关系,相应的结构称为逻辑结构。其要点有两个方面:一是元素本身,二是元素之间的关系。数据元素之间的逻辑结构有四种基本类型,如下:

云淡风清 http://gsqls.blog.163.com/

①集合:结构中的数据元素除了“同属于一个集合”外,没有其它关系。 ②线性结构:结构中相邻的数据元素之间存在一对一的关系。 ③树型结构:结构中相邻的数据元素之间存在一对多的关系。

④图状结构或网状结构:结构中相邻的数据元素之间存在多对多的关系。 数据结构数学形式的定义是一个二元组: DataStructure=(D,S) 其中:D是数据元素的有限集,S是D上关系的有限集。 例:设数据逻辑结构B=(K,R),其中: K={k1, k2, …, k9}

R={,,,,,,,,,,} 画出这逻辑结构的图示,并确定哪些是起点,哪些是终点。

1.2.5数据的物理结构:

又称存储结构,指数据结构在计算机内存中的存储方式。

数据结构在计算机内存中的存储包括数据元素的存储和元素之间的关系的存储。 元素之间的关系在计算机中有两种不同的表示方法:顺序表示和非顺序表示。由此得出两种不同的存储结构:顺序存储结构和链式存储结构。

顺序存储结构:用数据元素在存储器中的相对位置来表示数据元素之间的逻辑结构(关系)。 链式存储结构:在每一个数据元素中增加一个存放另一个元素地址的指针(pointer),用该指针来表示数据元素之间的逻辑结构(关系)。

例:设有数据集合A={3.0,2.3,5.0,-8.5,11.0},两种不同的存储结构。 顺序结构:数据元素存放的地址是连续的;

链式结构:数据元素存放的地址是否连续没有要求。

数据的逻辑结构和物理结构是密不可分的两个方面,一个算法的设计取决于所选定的逻辑结构,而算法的实现依赖于所采用的存储结构。

在C语言中,用一维数组表示顺序存储结构;通过结构体类型实现的链表来表示链式存储结构。

1.2.6数据结构(Data Structure):

按某种逻辑关系组织起来的一批数据,按一定的映象方式把它存放在计算机存贮器中,并在这些数据上定义了一个运算的集合,就叫做数据结构。

1.2.7数据结构的三个组成部分:

逻辑结构:数据元素之间逻辑关系的描述:D_S=(D,S)。

存储结构:数据元素在计算机中的存储及其逻辑关系的表现称为数据的存储结构或物理结构。 数据操作:对数据要进行的运算。

本课程中将要讨论的三种逻辑结构及其采用的存储结构如下图所示。

云淡风清 http://gsqls.blog.163.com/

逻辑结构与所采用的存储结构

数据逻辑结构层次关系图

1.2.8数据类型(Data Type):

指的是一个值的集合和定义在该值集上的一组操作的总称。

数据类型是和数据结构密切相关的一个概念。在C语言中数据类型有:基本类型(如int,float,double,char等)和构造类型(如数组,结构体,共用体等)。

数据结构不同于数据类型,也不同于数据对象,它不仅要描述数据类型的数据对象,而且要描述数据对象各元素之间的相互关系。

1.3数据结构的运算

数据结构的主要运算包括: ⑴建立(Create)一个数据结构; ⑵消除(Destroy)一个数据结构;

⑶从一个数据结构中删除(Delete)一个数据元素; ⑷把一个数据元素插入(Insert)到一个数据结构中; ⑸对一个数据结构进行访问(Acce);

⑹对一个数据结构(中的数据元素)进行修改(Modify); ⑺对一个数据结构进行排序(Sort); ⑻对一个数据结构进行查找(Search)。

以上只列举了一些常见运算,实际应用当中可能会遇到许多其它运算。

云淡风清 http://gsqls.blog.163.com/ 1.4抽象数据类型(Abstract Data Type) 1.4.1抽象数据类型简介:

简称ADT,是指一个数学模型以及定义在该模型上的一组操作。ADT的定义仅是一组逻辑特性描述,与其在计算机内的表示和实现无关。因此,不论ADT的内部结构如何变化,只要其数学特性不变,都不影响其外部使用。

ADT的形式化定义是三元组:ADT=(D,S,P) 其中:D是数据对象,S是D上的关系集,P是对D的基本操作集。 说明:

⑴ADT和数据类型实质上是一个概念,其区别是:ADT的范畴更广,它不再局限于系统已定义并实现的数据类型,还包括用户自己定义的数据类型。

⑵ADT的定义是由一个值域和定义在该值域上的一组操作组成。包括定义,表示和实现三个部分。 ⑶ADT的最重要的特点是抽象和信息隐蔽。抽象的本质就是抽取反映问题本质的东西,忽略非本质的细节,使所设计的结构更具有一般性,可以解决一类问题。信息隐蔽就是对用户隐藏数据存储和操作实现的细节,使用者了解抽象操作或界面服务,通过界面中的服务来访问这些数据。

ADT不考虑物理结构以及算法的具体实现。

例:整数的数学概念和对整数所能进行的运算构成一个ADT,C语言中的变量类型int就是对这个抽象数据类型的一种物理实现。

1.4.2ADT的一般定义形式:

ADT的一般定义形式是: ADT { 数据对象: 数据关系: 基本操作: }ADT 其中数据对象和数据关系的定义用伪码描述。 基本操作的定义是: () 初始条件: 操作结果: 说明:

初始条件:描述操作执行之前数据结构和参数应满足的条件;若不满足,则操作失败,返回相应的出错信息。

操作结果:描述操作正常完成之后,数据结构的变化状况和应返回的结果。

1.5算法(Algorithm) 1.5.1算法基本概念:

算法是对特定问题求解方法(步骤)的一种描述,是指令的有限序列,其中每一条指令表示一个或

云淡风清 http://gsqls.blog.163.com/ 多个操作。

1.5.2算法的基本特征:

算法具有以下五个特性

①有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。

②确定性:算法中每一条指令必须有确切的含义。不存在二义性。且算法只有一个入口和一个出口。

③可行性:一个算法是能行的。即算法描述的操作都可以通过已经实现的基本运算执行有限次来实现。

④输入:一个算法有零个或多个输入,这些输入取自于某个特定的对象集合。

⑤输出:一个算法有一个或多个输出,这些输出是同输入有着某些特定关系的量。

1.5.3算法的基本描述方法:

一个算法可以用多种方法描述,主要有:使用自然语言描述;使用形式语言描述;使用计算机程序设计语言描述等。

1.5.4算法与程序的异同比较:

算法和程序是两个不同的概念。一个计算机程序是对一个算法使用某种程序设计语言的具体实现。算法必须可终止意味着不是所有的计算机程序都是算法。

1.5.5评价算法好坏的几个标准:

评价一个好的算法有以下几个标准

①正确性(Correctne):算法应满足具体问题的需求。

②可读性(Readability):算法应易于供人阅读和交流。可读性好的算法有助于对算法的理解和修改。

③健壮性(Robustne):算法应具有容错处理。当输入非法或错误数据时,算法应能适当地做出反应或进行处理,而不会产生莫名其妙的输出结果。

④通用性(Generality):算法应具有一般性,即算法的处理结果对于一般的数据集合都成立。 ⑤效率与存储容量需求:效率指的是算法执行的时间;存储容量需求指算法执行过程中所需要的最大存储空间。一般地,这两者与问题的规模有关。

1.6算法效率的度量

解决同一个问题的算法可能有多种,如何选择一个效率高的算法呢?应该来讲,与算法效率相关的因素有很多,如下:

云淡风清 http://gsqls.blog.163.com/

1、算法选用何种策略;

2、问题的规模;

3、程序设计的语言;

4、编译程序所产生的机器代码的质量;

5、内存的大小;

6、外存的大小;

7、机器执行指令的速度;

8、其它。

而确定算法效率的方法通常有两种:

1.6.1事后统计:

先实现算法,然后运行程序,测算其时间和空间的消耗。 缺点:

1、必须先依据算法编制程序并运行程序,耗费人力物力;

2、依赖软硬件环境,容易掩盖算法本身的优劣。由于算法的运行与计算机的软硬件等环境因素有关,不容易发现算法本身的优劣。同样的算法用不同的编译器编译出的目标代码数量不同,完成算法所需的时间也不同;若计算机的存储空间较小,算法运行时间也就会延长;

3、没有实际价值。测试花费不少时间但并没有解决现实中的实际问题。

1.6.2事前分析:

仅仅通过比较算法本身的复杂性来评价算法的优劣,不考虑其它的软硬件因素,通常考查算法所用的时间和所需的存储空间。

算法复杂性的度量可以分为时间复杂度和空间复杂度。

1.6.3算法的时间复杂度(Time complexity)

1、算法的时间复杂度

算法的时间复杂度用于度量一个算法所用的时间。

算法所用的时间主要包括程序编译时间和运行时间。由于一个算法一旦编译成功可以多次运行,因此可以忽略编译时间,只讨论算法的运行时间。

算法的运行时间依赖于加、减、乘、除、等基本的运算以及参加运算的数据量的大小,另外,与计算机硬件和操作环境等也有关系。要想准确地估算时间是不可行的,而影响算法时间最为主要的因素是问题的规模,即输入量的多少。同等条件下,问题的规模越大,算法所花费的时间也就越长。例如,求1+2+3+„+n的算法,即n个整数的累加求和,这个问题的规模为n。因此,运行算法所需的时间T是问题规模n的函数,记作T(n)。

同等条件下,相同或类似的基本操作在真正程序运行过程中所花费的时间也差不多,这样,如果两个不同算法中一个所含基本操作多而另一个所含基本操作少,则包含基本操作少的算法其花费时间也就较少。因此,通常用算法中基本语句的执行次数来作为度量算法速度快慢的依据,而这种度量时间复杂度的方法得出的不是时间量,而是一种增长趋势的度量,即当问题规模n增大时,T(n)也随之变大。换言之,当问题规模充分大时,算法中基本语句的执行次数为在渐进意义下的阶,称为算法的渐进时间复杂度,简称时间复杂度,通常用大O记号表示。用数学语言通常描述为:若当且仅当存在正整数n和n0,对于任意n≥n0,都有T(n)≤c×f(n),则称该算法的渐进时间复杂度为T(n)=O(f(n))。

一般地,常用最内层循环内的语句中的原操作的执行频度(重复执行的次数)来表示时间复杂度。

2、时间复杂度分析举例: 例:两个n阶方阵的乘法。

云淡风清 http://gsqls.blog.163.com/ for(i=1;i

c[i][j]=0;

for(k=1;k

c[i][j]+=a[i][k]*b[k][j]; } 分析:由于是一个三重循环,每个循环从1到n,则总次数为: n×n×n=n3,时间复杂度为T(n)=O(n3)。

例: { ++x; s=0; } 分析:将x自增看成是基本操作,则语句频度为1,即时间复杂度为O(1) 。

如果将s=0也看成是基本操作,则语句频度为2,其时间复杂度仍为O(1),即常量阶。 只要T(n)不是问题规模n的函数,而是一个常数,它的时间复杂度则均为O(1)。 例:以下程序段: for(i=1;i

++x;

s+=x; } 分析:基本语句的语句频度为:n2 ,其时间复杂度为:O(n2),即为平方阶。

定理:若T(n)=amnm+am-1nm-1+„+a1n+a0是一个m次多项式,则T(n)=O(nm),即复杂度表达式只取一个n趋向于无穷大时的同阶无穷小表达式即可。

通过对算法复杂度的分析,总结出这样一条结论,在计算任何算法的复杂度时,可以忽略所有低次幂和最高次幂的系数,这样可以简化算法分析,并使注意力集中在增长率上。

从本质上来讲,此种策略也就是只考虑对算法复杂度影响最大的因素而忽略次要因素。 例:以下程序段:

for(i=2;i

for(j=2;j

{

++x;

a[i,j]=x;

}

云淡风清 http://gsqls.blog.163.com/ 分析:基本语句的语句频度为: 1+2+3+„+n-2 =(1+n-2)×(n-2)/2

=(n-1)×(n-2)/2 =(n2-3n+2)/2 按上述定理,时间复杂度为O(n2),即此算法的时间复杂度为平方阶。

一个算法时间复杂度为O(1)的算法,它的基本运算执行的次数是固定的。因此,总的时间由一个常数(即零次多项式)来界定。而一个时间为O(n2)的算法则由一个二次多项式来界定。

3、常见表示时间复杂度的阶: O(1):常量时间阶 O(n):线性时间阶 O(㏒n):对数时间阶

O(n㏒n):线性对数时间阶 O(nk):k≥2,k次方时间阶

4、常见时间复杂度大小关系分析:

以下六种计算算法时间复杂度的多项式是最常用的,其大小关系通常为: O(1)

当n取得很大时,指数时间算法和多项式时间算法在所需时间上非常悬殊。因此,只要有人能将现有指数时间算法中的任何一个算法化简为多项式时间算法,那就取得了一个伟大的成就。

有的情况下,算法中基本操作重复执行的次数还随输入数据集的不同而不同。 例:素数的判断算法。

void prime(int n)//n是一个正整数 { int i=2; while((n%i)!=0 && i*1.0

i++; if(i*1.0>sqrt(n))

printf("&d 是一个素数\n",n); else

printf("&d 不是一个素数\n",n); } 此例中执行频率最高的语句为i++;,此语句最少执行0次,最多执行sqrt(n)次,对于不同的n,执行次数不确定。

对于此类算法,如果输入数据不同,则算法运行时间也不同,因此要全面分析一个算法,需要考虑算法在最好、最坏、平均情况下的时间消耗。由于最好情况出现的概率太小,因此不具代表性,但是,当最好情况出现的概率大时,应该分析最好情况;虽然最坏情况出现的概率也太小,不具代表性,但是分析最坏情况能够让人们知道算法的运行时间最坏能到什么程度,这一点在实时系统中很重要;分析平均情况是比较普遍的,特别是同一个算法要处理不同的输入时,通常假定输入的数据是等概率分布的。

例:冒泡排序法。

void bubble_sort(int a[],int n)

云淡风清 http://gsqls.blog.163.com/ { int temp; change=false; for(i=n-1;change=TURE;i>1 && change;--i)

for(j=0;j

if(a[j]>a[j+1])

{

temp=a[j];

a[j]=a[j+1];

a[j+1]=temp;

change=TURE;

} } 最好情况:0次

最坏情况:1+2+3+⋯+n-1=n(n-1)/2平均时间复杂度为:O(n2) 1.6.4算法的空间复杂度(Space complexity)

1、算法的空间复杂度

算法的空间复杂度是指在算法的执行过程中需要的辅助空间数量。辅助空间数量指的不是程序指令、常数、指针等所需要的存储空间,也不是输入数据所占用的存储空间,辅助空间是除算法本身和输入输出数据所占据的空间外,算法临时开辟的存储空间。算法的空间复杂度分析方法同算法的时间复杂度相似,设S(n)是算法的空间复杂度,通常可以表示为:

S(n)=O(f(n)) 其中:n为问题的规模(或大小)。 该存储空间一般包括三个方面: 指令常数变量所占用的存储空间; 输入数据所占用的存储空间; 辅助(存储)空间。

一般地,算法的空间复杂度指的是辅助空间。 如:

一维数组a[n]:空间复杂度O(n) 二维数组a[n][m]:空间复杂度O(n*m) 例:数组a中有10000个数,要求将所有数据逆置(即顺序倒过来存放)。 为达到逆置目的,有以下两种方案: 方案一:

int a[10000],b[10000],i; for(i=0;i

int a[10000],t,i; for(i=0;i

云淡风清 http://gsqls.blog.163.com/ { t=a[i]; a[i]=a[10000-i-1]; a[10000-i-1]=t; } 很明显,方案二中的辅助空间数量为1,而方案一中的辅助空间数量为10000,方案二的空间复杂度优于方案一。

在算法的时间复杂度和空间复杂度中,我们更注重算法的时间性能。因此,在对算法性能的分析当中,通常均主要针对算法时间性能进行分析。

1.6.5学习算法的原因

讲述了这么多关于算法的基础知识,究竟为什么要学习算法呢?

首先,算法无处不在。算法不仅出现在数学和计算机程序中,更普遍地出现在我们的生活中,在生活中做什么事情都要有一定的顺序,然而不同的顺序带来的效率和成果可能都会不同,只有学好了算法,才能让生活更有趣、更有效率。

其次,算法是程序的灵魂。学习计算机编程,必须要掌握好其灵魂,否则,写出来的程序就像是没有灵魂的躯体。

再次,算法是一种思想。掌握了这种思想,能够拓展思维,使思维变得清晰、更具逻辑性,在生活以及编程上的很多问题,也就更易解决。

最后,算法的乐趣。学习算法不仅仅是为了让它帮助人们更有效地解决各种问题,算法本身的趣味性很强,当通过烦琐的方法解决了一个问题后会感觉到有些疲惫,但是面对同一个问题,如若学会使用算法,更简单有效地解决了这个问题,会发现很有成就感,算法的速度、思想会让人觉得很奇妙。每一个奇妙的算法都是智慧的结晶。

学习算法的理由成千上万,不同的人可能出于不同的目的去学习算法,希望大家能够通过对课程的学习对算法有进一步的理解。

习题一

1、简要回答术语:数据,数据元素,数据结构,数据类型。

2、数据的逻辑结构?数据的物理结构?逻辑结构与物理结构的区别和联系是什么?

3、数据结构的主要运算包括哪些?

4、算法分析的目的是什么?算法分析的主要方面是什么?

云淡风清 http://gsqls.blog.163.com/

第2章 线性表

下表为某电台提供给听众的若干首英文歌曲名及相关点播情况统计信息:

由于实际的歌曲库可能很大,手工管理效率低,不方便,现请设计一个软件系统实现对此类歌曲库的管理。

分析:

此例中相邻的两首歌之间是一种一对一的关系,属于典型的线性结构,可按线性结构进行组织及管理。

2.1线性结构与线性表 2.1.1线性结构

如果一个数据元素序列满足:

⑴除第一个和最后一个数据元素外,每个数据元素只有一个直接前驱数据元素和一个直接后继数据元素;

⑵第一个数据元素没有前驱数据元素; ⑶最后一个数据元素没有后继数据元素。 则称这样的数据结构为线性结构。

线性表、栈、队列、串和数组都属于线性结构。 如下图:

云淡风清 http://gsqls.blog.163.com/ 2.1.2线性表

线性表(Linear List)是一种最简单、最常用的线性结构,是一种可以在任意位置进行插入和删除数据元素操作的、由n(n≥0)个相同类型数据元素a1,a2,„,an组成的线性结构。在这种结构中:

⑴存在一个唯一的被称为“第一个”的数据元素; ⑵存在一个唯一的被称为“最后一个”的数据元素; ⑶除第一个元素外,每个元素均有唯一一个直接前驱; ⑷除最后一个元素外,每个元素均有唯一一个直接后继。 线性表中的数据元素的个数n称为线性表的长度。 当n=0时,称为空表。空线性表用符号()表示。

当n>0时,将非空的线性表记作:(a1,a2,„an),其中符号ai(1≤i≤n)表示第i个抽象数据元素。

a1称为线性表的第一个(头)结点,an称为线性表的最后一个(尾)结点。 a1,a2,„ai-1都是ai(2≤i≤n)的前驱,其中ai-1是ai的直接前驱;

ai+1,ai+2,„an都是ai(1≤i ≤n-1)的后继,其中ai+1是ai的直接后继。

线性结构是最常用、最简单的数据结构,而线性表是一种典型的线性结构,其基本特点是可以在任意位置进行插入和删除等操作,且数据元素是有限的。

线性表可以用顺序存储结构或链式存储结构实现。用顺序存储结构实现的线性表称为顺序表,用链式存储结构实现的线性表称为链表。链表主要有单链表、循环单链表和循环双链表三种。顺序表和链表各有优缺点,并且优缺点刚好相反,在实际应用中要根据情况选择对操作及性能有利的存储结构。

线性表中的数据元素ai所代表的具体含义随实际应用领域的不同而不同,在线性表的定义中,只不过是一个抽象的表示符号。

◆线性表中的结点可以是单值元素(每个元素只有一个数据项) 。 例1:26个英文字母组成的字母表:(A,B,C、„、Z) 例2:某校从1978年到1983年各种型号的计算机拥有量的变化情况:(6,17,28,50,92,188) 例3:一副扑克的点数:(2,3,4,„,J,Q,K,A) ◆线性表中的结点可以是记录型元素,每个元素含有多个数据项 ,每个项称为结点的一个域 。每个元素有一个可以唯一标识每个结点的数据项组,称为关键字。

例4:某校2001级同学的基本情况:{(‘2001414101’,‘张里户’,‘男’,06/24/1983), (‘2001414102’,‘张化司’,‘男’,08/12/1984) „, (‘2001414102’,‘李利辣’,‘女’,08/12/1984) } ◆若线性表中的结点是按值(或按关键字值)由小到大(或由大到小)排列的,称线性表是有序的。 ◆线性表是一种相当灵活的数据结构,其长度可根据需要增长或缩短。

◆对线性表的基本操作如下(实际应用中要根据需要选择相应操作或者添加未列出的操作): ⑴建立空表L ⑵返回表L的长度,即表中元素个数 ⑶取线性表L中位置i处的元素(1≤i≤n) ⑷取i的直接前驱元素 ⑸取i的直接后继元素

⑹查询元素x在L中的逻辑位置

⑺在线性表L的位置i处插入元素x,原位置元素后移一个位置 ⑻从线性表L中删除位置i处的元素 ⑼判断线性表是否为空 ⑽清空已存在的线性表 ⑾遍历所有元素

云淡风清 http://gsqls.blog.163.com/ ⑿根据所给关键字查询元素并返回其详细信息 ⒀修改表中元素

⒁对所有元素按条件排序

2.1.3线性表的抽象数据类型定义

ADT List { 数据对象:D = { ai | ai∈ElemSet, i=1,2,„,n, n≥0 } 数据关系:R = { | ai-1, ai∈D, i=2,3,„,n } 基本操作: InitList(&L) 初始条件:无

操作结果:构造一个空的线性表L; ListLength(L) 初始条件:线性表L已存在;

操作结果:返回线性表中的元素个数; GetElem(L,i,e) 初始条件:线性表L已存在,1≤i≤ListLength(L); 操作结果:用e返回L中第i个数据元素的值; ListInsert(L,i,e) 初始条件:线性表L已存在,1≤i≤ListLength(L)+1,线性表未满;

操作结果:在线性表L中的第i个位置插入元素e,原来位置及以后的元素都后移; ListLocate(L,e) 初始条件:线性表L已存在;

操作结果:返回元素e在L中的逻辑位置,不存在则返回0; ListDelete(L,i) 初始条件:线性表L已存在,1≤i≤ListLength(L); 操作结果:从表L中删除位置i处的元素; ListClear(L) 初始条件:线性表L已存在; 操作结果:清空已存在的表; ListTraverse(L) 初始条件:线性表L已存在; 操作结果:遍历输出所有元素; ListUpdate(L,i,e) 初始条件:线性表L已存在,1≤i≤ListLength(L); 操作结果:将线性表L中第i个位置的值置为e; ListSort(L) 初始条件:线性表L已存在;

操作结果:按一定条件对所有元素重新排序; ListDestroy(L) 初始条件:线性表L已存在; 操作结果:释放线性表空间; …

云淡风清 http://gsqls.blog.163.com/ } ADT List 2.2线性表的顺序存储 2.2.1线性表的顺序存储结构

顺序存储:把线性表的结点按逻辑顺序依次存入地址连续的一组存储单元里。用这种方法存储的线性表简称顺序表。

顺序存储的线性表的特点:

◆线性表的逻辑顺序与物理顺序一致;

◆数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现的。 设有非空的线性表:(a1,a2,„an) 。顺序存储如下图所示。

在具体的机器环境下,设线性表的每个元素需占用len个存储单元,以所占的第一个单元的存储地址作为数据元素的存储位置,则线性表中第i+1个数据元素的存储位置Loc(ai+1)和第i个数据元素的存储位置Loc(ai)之间满足下列关系:

Loc(ai+1)=Loc(ai)+l 线性表的第i个数据元素ai的存储位置为: Loc(ai)=Loc(a1)+(i-1)*len 高级语言中同一个数组的各个元素占用连续存储单元,具有随机存取(指存取同一数组各元素的时间开销相同,不受所处位置的限制)的特性,故而在高级语言中通常用数组来存储顺序表。除了用数组来存储线性表的元素之外,顺序表还应该表示线性表的长度属性以方便某些操作,所以用结构体类型来定义顺序表类型。

#include #include #define OK

1 #define ERROR

-1 #define MAX_SIZE 100 //最大长度 typedef int Status; //状态

typedef int ElemType;//元素类型,可根据实际需要更改 typedef struct Sqlist { ElemType *Elem_Array;//线性表存储空间地址

int Length;//线性表长度 } SqList; 注意:C语言中数组的下标值是从0开始,第i个元素的下标值是i-1 。

2.2.2顺序表的基本操作

顺序存储结构中,很容易实现线性表的一些操作:初始化、赋值、查找、修改、插入、删除、求长度等。

以下将对几种主要的操作进行讨论。 #include

云淡风清 http://gsqls.blog.163.com/ #include #define OK

1 #define ERROR

-1 #define MAX_SIZE 100 //最大长度 typedef int Status; //状态

typedef int ElemType;//元素类型,可根据实际需要更改 typedef struct Sqlist { ElemType Elem_Array[MAX_SIZE];//线性表存储空间地址

int Length;//线性表长度 } SqList; /*

1、初始化

构造一个空的线性表 */ Status Init_SqList(SqList *L) { L->Length=0; return OK; } /*

2、测长度

返回线性表中的元素个数 */ int Length_SqList(SqList *L) { return L->Length; } /*

3、取元素

用e返回L中第i个数据元素的值,1≤i≤ListLength(L) */ Status Get_SqList(SqList *L,int i,ElemType *e) { if((i>=1)&&(iLength)) {

*e=L->Elem_Array[i-1];//i位置对应的元素下标为i-1

return OK; } else

return ERROR; }

云淡风清 http://gsqls.blog.163.com/ /*

4、顺序线性表的插入

在线性表L中的第i个位置插入元素e,原来位置及以后的元素都后移。 要求1≤i≤ListLength(L)+1,线性表未满。 实现步骤:

(1)将线性表L中的第i个至第n个结点后移一个位置。 (2)将结点e插入到结点ai-1之后。

(3)线性表长度加1。 */ Status Insert_SqList(Sqlist *L,int i,ElemType e) { int j; if((iL->Length+1))//位置错误

return ERROR; else

if(L->Length>=MAX_SIZE)//线性表上溢

//实际开发中达到空间上限时可用remalloc()函数重新分配空间,扩大空间容量

return ERROR;

else

{

//i-1位置以后的所有结点后移

for(j=L->Length-1;j>=i-1;--j)

L->Elem_Array[j+1]=L->Elem_Array[j];

L->Elem_Array[i-1]=e;//在i-1位置插入结点

L->Length++;//线性表长度增1

return OK;

} } /* 时间复杂度分析:

在线性表L中的第i个位置插入新结点,其时间主要耗费在表中结点的移动操作上,因此,可用结点的移动来估计算法的时间复杂度。

设在线性表L中的第i个位置插入结点的概率为Pi,不失一般性,设各个位置插入是等概率,则Pi=1/(n+1),而插入时移动结点的次数为n-i+1。

总的平均移动次数:Einsert=∑pi*(n-i+1) (1≤i≤n) 计算得:Einsert=n/2。

即在顺序表上做插入运算,平均要移动表上一半结点,当表长n较大时,算法的效率相当低。因此算法的平均时间复杂度为O(n)。

*/ /*

5、线性表元素位置查询

返回元素e在L中的逻辑位置,不存在则返回0

云淡风清 http://gsqls.blog.163.com/ */ int Locate_SqList(Sqlist *L,ElemType e) { int i,found=0;//found用于表示是否找到,0:未找到 1:找到

i=0;//从第一个开始查询

while((iLength)&&(found==0))

if(L->Elem_Array[i]==e)

found=1;

else

i++; if(found==1)

return i+1;//返回逻辑位置编号

else

return 0;//未找到,返回0 } /*

6、删除指定位置元素 在线性表:

L=(a1,„ai-1,ai, ai+1,„,an) 中删除结点ai(1≦i≦n),使其成为线性表: L= (a1,„ai-1,ai+1,„,an) 要求1≤i≤ListLength(L),线性表未空。 实现步骤:

(1)将线性表L中的第i+1个至第n个结点依此向前移动一个位置。 (2)线性表长度减1。 */ Status Delete_SqList(Sqlist *L,int i) { int k; if(L->Length==0)//线性表空

{

printf("线性表L为空!\n");

return ERROR; } else

if(iL->Length)//指定位置不合适

{

printf("要删除的数据元素不存在!\n");

return ERROR;

}

else

{

//i位置以后的所有结点前移

for(k=i;kLength;k++)

L->Elem_Array[k-1]=L->Elem_Array[k];

云淡风清 http://gsqls.blog.163.com/

L->Length--;//线性表长度减1

return (OK);

} } /* 时间复杂度分析:

删除线性表L中的第i个元素,其时间主要耗费在表中结点的移动操作上,因此,可用结点的移动来估计算法的时间复杂度。

设在线性表L中删除第i个元素的概率为Pi,不失一般性,设删除各个位置是等概率,则Pi=1/n,而删除时移动结点的次数为n-i。

则总的平均移动次数:Edelete=∑Pi*(n-i)

(1≤i≤n) 计算得:Edelete=(n-1)/2 即在顺序表上做删除运算,平均要移动表上一半结点,当表长n较大时,算法的效率相当低,因此算法的平均时间复杂度为O(n)。

*/ /*

7、清空 */ Status Clear_SqList(Sqlist *L) { L->Length=0; return OK; } /*

8、遍历 以输出为例 */ Status Traverse_SqList(Sqlist *L) { int i; printf("共有%d个元素,以下为具体内容:\n",L->Length); for(i=0;iLength;i++)

printf("%8d",L->Elem_Array[i]); printf("\n------------------END------------------\n"); return OK; } /*

9、修改

将线性表L中第i个位置的值置为e。要求线性表L已存在且1≤i≤ListLength(L)。 */ Status Update_SqList(Sqlist *L,int i,ElemType e) { if((iL->Length))//位置错误

云淡风清 http://gsqls.blog.163.com/

return ERROR; else {

L->Elem_Array[i-1]=e;//放置新数据

return OK; } } /*

10、排序

按要求对线性表中元素排序。 */ Status Sort_SqList(Sqlist *L) { int i,j; ElemType temp; for(i=1;iLength-1;i++)

for(j=0;jLength-i-1;j++)

{

if(L->Elem_Array[j]Elem_Array[j+1])

{

temp=L->Elem_Array[j];

L->Elem_Array[j]=L->Elem_Array[j+1];

L->Elem_Array[j+1]=temp;

}

} return OK; } /* 主函数 */ void main() { int xz=1,i; SqList L; ElemType e; while(xz!=0) {

printf("

1、初始化\n

2、测长度\n

3、取元素\n

4、插入\n

5、查询\n

6、删除\n

7、清空\n

8、遍历\n

9、修改\n

10、排序\n 0、结束\n请选择:");

scanf("%d",&xz);

switch(xz)

{

case 1:

if(Init_SqList(&L)==OK)

云淡风清 http://gsqls.blog.163.com/

printf("初始化成功!\n"); else

printf("初始化未成功!\n"); break; case 2: printf("线性表长度为:%d\n",Length_SqList(&L)); break; case 3: printf("请输入要取元素的位置:"); scanf("%d",&i); if(Get_SqList(&L,i,&e)==OK)

printf("指定位置上的元素为:%d\n",e); else

printf("Error!\n"); break; case 4: printf("请输入要插入的位置:"); scanf("%d",&i); printf("请输入要插入的元素内容:\n"); scanf("%d",&e); if(Insert_SqList(&L,i,e)==OK)

printf("插入成功\n"); else

printf("Error!\n"); break; case 5: printf("请输入要查询的元素内容:"); scanf("%d",&e); printf("此元素逻辑位置为:%d(0表示未找到)。\n",Locate_SqList(&L,e)); break; case 6: printf("请输入要删除元素的位置:"); scanf("%d",&i); if(Delete_SqList(&L,i)==OK)

printf("删除成功\n"); else

printf("Error!\n"); break; case 7: Clear_SqList(&L); break; case 8: Traverse_SqList(&L); break;

云淡风清 http://gsqls.blog.163.com/

case 9:

printf("请输入要修改的元素位置:");

scanf("%d",&i);

printf("请输入元素的新内容:\n");

scanf("%d",&e);

if(Update_SqList(&L,i,e)==OK)

printf("修改成功\n");

else

printf("Error!\n");

break;

case 10:

Sort_SqList(&L);

printf("排序完成!\n");

break;

case 0:

printf("谢谢使用,再见!\n");

break;

default:

printf("输入错误!\n");

break;

} } } 需要说明的是,本例没有实现空间的动态分配,若要实现动态分配,可参照第三章“栈的动态顺序存储结构”的做法。

2.2.3顺序存储线性表的特点

优点:表中任意一个结点的存取很方便,可以进行随机存取,处于不同位置上的结点的存取时间从理论上来说相同,也能进行插入和删除操作。

缺点:

(1)插入和删除不方便。为保持连续存放,操作中需要移动大量元素。

(2)会造成空间的浪费以及不易扩充。所占空间通常情况下大小固定,处理长度变化较大的线性表时,分配空间大小不够,会造成溢出;分配空间太大,会造成浪费。

2.3线性表的链式存储 2.3.1线性表的链式存储结构

链式存储:用一组任意(即不必要连续)的存储单元存储线性表中的数据元素。用这种方法存储的线性表简称线性链表。

链表中结点所占用的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的,链表中结点的逻辑顺序和物理顺序不一定相同。

为了正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其直接后继结点的

云淡风清 http://gsqls.blog.163.com/ 地址(或位置),称为指针(pointer)或链(link),这两部分组成了链表中的结点结构,如下图所示。

data:数据域,存放结点的值。

next:指针域,存放结点的直接后继的地址。

链表通过每个结点的指针域将线性表的n个结点按其逻辑次序链接在一起。每一个结点只包含一个指针域的链表,称为单链表。

为操作方便,总是在链表的第一个结点之前附设一个头指针变量head指向第一个结点。头结点的数据域可以不存储任何信息(或存放链表长度等辅助信息),此时通常称为带头结点的单链表。当然,也可以让头结点的数据域存放有效数据,此时称为不带头结点的单链表。相对而言,带头结点的单链表浪费了一个结点的数据域,但会给编程带来一定方便。

带头结点的单链表其基本结构如下:

说明:

(1)整个链表由若干个结点组成,一个结点占用一个内存块,而每个结点又分为两大部分:数据域和指针域,其中数据域存放用户数据,指针域用于存放后一个结点的地址,通过指针域将逻辑上前后相邻的结点连接起来,这样,通过前一个结点指针域中存放的地址就可以找到后一个结点。可看出,每个结点的指针域实际上充当了指针变量的角色,只要结点数可变,则意味着指针变量数也可变,而事实上结点所对应的这些内存块完全可以多次动态分配,这也就意味着指针域(相当于指针变量)的个数可以根据需要动态调整,这就解决了前述的“程序中变量个数固定,但问题本身所需变量个数不定”的矛盾。

(2)设置一个头指针变量指向首结点,在带头结点的单链表中,此结点不存放有效数据。 (3)末尾结点的指针域设置为空“NULL”表示链表的结束,相当于字符串中的'\0'。

(4)在没有用户数据的情况下,此链表只有一个结点,此结点既是首结点,又是末结点,结点的指针域为“NULL”,此时表示链表为逻辑“空”,也就是说,链表的初始状态应该如下图所示。

单链表是由表头唯一确定的,因此单链表可以用头指针的名字来命名。 例

1、线性表L=(bat,cat,eat,fat,hat) 其带头结点的单链表的逻辑状态和物理存储方式如下图所示。

云淡风清 http://gsqls.blog.163.com/

1、结点的描述与实现

C语言中用带指针的结构体类型来描述 typedef int ElemType; typedef struct Lnode { ElemType

data;//数据域,保存结点的值

struct

Lnode *next;//指针域,保存后继结点地址 }LNode;

//结点的类型

2、结点空间分配及回收的实现

结点存储空间是通过动态内存分配和释放来实现的,即需要时分配,不需要时释放。在C语言中可通过标准函数:malloc() ,realloc(),sizeof(),free()等来实现分配。

动态分配:p=(LNode*)malloc(sizeof(LNode)); 函数malloc分配了一个类型为LNode的结点变量的空间,并将其首地址放入指针变量p中。 动态释放:free(p) ; 系统回收由指针变量p所指向的内存区。p必须是最近一次调用malloc()函数时的返回值。 动态重新分配:p= (LNode*)realloc(p,newsize); 先判断当前的指针是否有足够的连续空间,如果有,扩大p指向的地址,并且将p返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来p所指内存区域,同时返回新分配的内存区域的首地址,即重新分配存储器块的地址。返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

3、最常用的基本操作 ⑴ 结点的赋值 LNode *p; p=(LNode*)malloc(sizeof(LNode)); p->data=20; p->next=NULL;讲课时板书教案上的几种常见的指针操作。 效果如下图。

⑵常见的指针操作 ①q=p;

云淡风清 http://gsqls.blog.163.com/ ②q=p->next;

③p=p->next;

④q->next=p;

⑤q->next=p->next;

云淡风清 http://gsqls.blog.163.com/

2.3.2单链式的基本操作

以带头结点的单链表为例。 #define OK

1 #define ERROR

-1 typedef int Status; //状态 #include "stdlib.h" #include "stdio.h" typedef int ElemType; typedef struct Lnode { ElemType

data;//数据域,保存结点的值

struct

Lnode *next;//指针域,保存后继结点地址 }LNode;

//结点的类型

/*

1、链表初始化(建立空链表) */ LNode * Init_LinkList(void) { LNode *L; L=(LNode *)malloc(sizeof(LNode));//给头结点分配空间

if(L!=NULL)

L->next=NULL;//指针域置为空以作为结束标记

return L; } /*

2、头插入法建表

从一个空表开始,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到读入结束标志为止,每次插入的结点都作为链表的第一个数据结点。

*/

云淡风清 http://gsqls.blog.163.com/ Status Create1_LinkList(LNode *L) { ElemType data; char sfjx=1;//0:结束 1:继续

LNode *p; while(sfjx!=0) {

p=(LNode *)malloc(sizeof(LNode));//给新结点分配空间

if(p==NULL)

return ERROR;//空间分配不成功

else

{

printf("请输入元素内容:");

scanf("%d",&data);//读入值

p->data=data;//数据域赋值

//钩链,新创建的结点总是作为第一个数据结点

p->next=L->next;

L->next=p;

}

printf("是否继续(0:结束 1:继续):");

scanf("%d",&sfjx); } return OK; } /*

3、尾插入法建表

头插入法建立链表虽然算法简单,但生成的链表中结点的次序和输入的顺序相反。若希望二者次序一致,可采用尾插法建表。

该方法是将新结点插入到当前链表的表尾,使其成为当前链表的尾结点。 */ Status Create2_LinkList(LNode *L) { ElemType data; char sfjx=1;//0:结束 1:继续

LNode *p,*q; //找到已有链表的末结点

q=L; while(q->next!=NULL)

q=q->next; while(sfjx!=0) {

p=(LNode *)malloc(sizeof(LNode));//给新结点分配空间

if(p==NULL)

云淡风清 http://gsqls.blog.163.com/

return ERROR;//空间分配不成功

else

{

printf("请输入元素内容:");

scanf("%d",&data);//读入值

p->data=data;//数据域赋值

//钩链,新创建的结点总是作为最后一个结点

q->next=p;

q=p;//q重新指向末结点

}

printf("是否继续(0:结束 1:继续):");

scanf("%d",&sfjx); } q->next=NULL;//重设链表结束标记

return(OK); } /*

4、按序号查找,取单链表中的第i个元素。

对于单链表,不能象顺序表中那样直接按序号i访问结点,而只能从链表的头结点出发,沿链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。

设单链表的长度为n,要查找表中第i个结点,仅当1≦i≦n时,i的值是合法的。 */ Status Get_LinkList(LNode *L,int i,ElemType *e) {

int j=1; LNode *p; p=L->next;//使p指向第一个结点

while((p!=NULL)&&(j

p=p->next;//移动指针p

j++;

//j计数

} if(p==NULL)//找不到

return(ERROR); else {

*e=p->data;

return(OK); } } /*

云淡风清 http://gsqls.blog.163.com/

5、按值查找

按值查找是在链表中,查找是否有结点值等于给定值key的结点? 若有,则返回首次找到的值为key的结点的存储位置;否则返回NULL。

*/ LNode *Locate_LinkList(LNode *L,ElemType key) { LNode *p; p=L->next; while((p!=NULL)&&(p->data!=key))

p=p->next; if(p!=NULL)//找到了

return p; else//找不到

return(NULL); } /*

6、单链表的插入,插入到指定位置

在以L为头结点的单链表的第i个位置插入值为e的结点。

插入运算是将值为e的新结点插入到表的第i个结点的位置上,即插入到ai-1与ai之间。因此,必须首先找到ai-1所在的结点p,然后生成一个数据域为e的新结点q,q结点作为p的直接后继结点。

*/ Status Insert_LinkList(LNode *L,int i,ElemType e) { int j=0; LNode *p,*q; p=L;//找待插入位置的前一个结点位置

while((p!=NULL)&&(j

p=p->next;

j++; } if((j!=i-1)||(p==NULL))//位置不合适

{

printf("位置不合适,无法插入!\n");

return ERROR; } else {

q=(LNode *)malloc(sizeof(LNode));//给新结点分配空间

if(q==NULL)

return ERROR;

else

云淡风清 http://gsqls.blog.163.com/

{

//实现插入

q->data=e;

q->next=p->next;

p->next=q;

return OK;

} } } /*

7、按序号删除

删除单链表中的第i个结点。

为了删除第i个结点ai,必须找到结点的存储地址。该存储地址是在其直接前趋结点ai-1的next域中,因此,必须首先找到ai-1的存储位置p,然后令p->next指向ai的直接后继结点,即把ai从链上摘下。最后释放结点ai的空间,将其归还给"存储池"。设单链表长度为n,则删去第i个结点仅当1≤i≤n时是合法的。则当i=n+1时,虽然被删结点不存在,但其前趋结点却存在,是终端结点。故判断条件之一是p->next!=NULL。显然此算法的时间复杂度也是O(n)。

*/ Status Delete1_LinkList(LNode *L,int i) { int j=1; LNode *p,*q; p=L; q=L->next;//找待删除位置的前一个结点位置

while(q!=NULL && j

p=q;

q=q->next;

j++; } if((q==NULL)||(i

printf("位置不合适,无法删除!\n ");

return ERROR; } else {

//实现删除

p->next=q->next;

free(q);

return OK; } }

云淡风清 http://gsqls.blog.163.com/ /*

8、按值删除

删除单链表中值为key的第一个结点。

与按值查找相类似,首先要查找值为key的结点是否存在? 若存在,则删除;否则返回NULL。 */ Status Delete2_LinkList(LNode *L,int key) { LNode *p=L,*q=L->next; //找待删除结点位置,q指向其位置,p指向其前驱结点

while(q!=NULL && q->data!=key) {

p=q;

q=q->next; } if(q!=NULL)//找到了

{

//实现删除

p->next=q->next;

free(q);

return OK; } else {

printf("所要删除的结点不存在!!\n");

return ERROR; } } /*

9、删除单链表中值为key的所有结点

与按值查找相类似,但比前面的算法更简单。

基本思想:从单链表的第一个结点开始,对每个结点进行检查,若结点的值为key,则删除之,然后检查下一个结点,直到所有的结点都检查。

*/ void Delete3_LinkList(LNode *L,int key) { LNode *p=L,*q=L->next; //p始终指向q的前驱,以方便删除操作的实现

while(q!=NULL) {

if(q->data==key)

{

p->next=q->next;

云淡风清 http://gsqls.blog.163.com/

free(q);

q=p->next;

}

else

{

p=q;

q=q->next;

} } } /*

10、删除单链表中所有值重复的结点,使得所有结点的值都不相同 与按值查找相类似,但比前面的算法更复杂。

基本思想:从单链表的第一个结点开始,对每个结点进行检查:检查链表中该结点的所有后继结点,只要有值和该结点的值相同,则删除之;然后检查下一个结点,直到所有的结点都检查。

*/ void Delete4_LinkList(LNode *L) { LNode *p=L->next,*q,*ptr; while(p!=NULL)//检查链表中所有结点

{

q=p;

ptr=p->next;

while(ptr!=NULL)//检查结点p的所有后继结点ptr

{

if(ptr->data==p->data)

{

q->next=ptr->next;

free(ptr);

ptr=q->next;

}

else

{

q=ptr;

ptr=ptr->next;

}

}

p=p->next; } } /*

云淡风清 http://gsqls.blog.163.com/

11、修改指定位置的数据 */ Status Modify_LinkList(LNode *L,int i,ElemType e) { int j=1; LNode *p; p=L->next;//找待修改结点位置

while(p!=NULL && j

p=p->next;

j++; } if((p==NULL)||(i

{

printf("位置不合适,无法修改!\n ");

return ERROR; } else {

p->data=e;

return OK; } } /*

12、单链表遍历 以输出为例 */ void Traverse_LinkList(LNode *L) { LNode *p; p=L->next; while(p!=NULL) {

printf("%8d",p->data);

p=p->next; } printf("\n"); } /*

13、单链表的合并

设有两个有序的单链表,它们的头指针分别是La、Lb,将它们合并为以Lc为头指针的有序链表。 算法说明:算法中pa,pb分别是待考察的两个链表的当前结点,pc是合并过程中合并的链表的最后一个结点。

云淡风清 http://gsqls.blog.163.com/

合并了值为-7,-2的结点后示意图如下图所示。

*/ LNode *Merge_LinkList(LNode *La,LNode *Lb) { LNode *Lc,*pa,*pb,*pc,*ptr; Lc=La; pc=La;//指向新链表的末结点

pa=La->next; pb=Lb->next; while(pa!=NULL && pb!=NULL) {

if(pa->datadata)//将pa所指的结点合并,pa指向下一个结点

{

pc->next=pa;

pc=pa;

pa=pa->next;

}

else

if(pa->data>pb->data) //将pb所指的结点合并,pb指向下一个结点

{

pc->next=pb;

pc=pb;

pb=pb->next;

云淡风清 http://gsqls.blog.163.com/

}

else//将pa所指的结点合并,pb所指结点删除

{

pc->next=pa;

pc=pa;

pa=pa->next;

ptr=pb;

pb=pb->next;

free(ptr);

} } //将剩余的结点链上

if(pa!=NULL)

pc->next=pa; else

pc->next=pb;

free(Lb); return(Lc); } /*

14、单链表的排序

采用插入排序方法,以升序为例 */ void Sort_LinkList(LNode *L) { LNode *p,*q,*r,*s; p=L->next; L->next=NULL; while(p!=NULL) {

q=L->next;

r=L;

while((q!=NULL)&&(p->data>q->data))

{

q=q->next;

r=r->next;

}

s=p->next;

r->next=p;

p->next=q;

p=s; } }

云淡风清 http://gsqls.blog.163.com/ /*

15、单链表的释放 */ void Release_LinkList(LNode *L) { LNode *p,*q; p=L;//指向头结点,从此结点开始释放

while(p!=NULL) {

q=p->next;

free(p);

p=q; } } void main() { int xz=1,i; LNode *L,*L1,*L2; ElemType e; while(xz!=0) {

printf("

1、链表初始化\n

2、头插入法建表\n

3、尾插入法建表\n

4、按序号查找\n

5、按值查找\n

6、单链表的插入\n");

printf("

7、按序号删除\n

8、按值删除\n

9、删除单链表中指定值的所有结点\n

10、删除单链表中所有值重复的结点\n");

printf("

11、修改指定位置的数据\n

12、单链表遍历\n

13、单链表的合并\n

14、单链表的排序\n

15、单链表的释放\n 0、结束\n请选择:");

scanf("%d",&xz);

switch(xz)

{

case 1:

L=Init_LinkList();

if(L!=NULL)

printf("初始化成功!\n");

break;

case 2:

if(Create1_LinkList(L)==OK)

printf("建立成功!\n");

else

printf("建立不成功!\n");

break;

case 3:

if(Create2_LinkList(L)==OK)

printf("建立成功!\n");

云淡风清 http://gsqls.blog.163.com/

else

printf("建立不成功!\n"); break; case 4: printf("请输入要查找元素的序号:"); scanf("%d",&i); if(Get_LinkList(L,i,&e)==OK)

printf("%d\n",e); else

printf("找不到!\n"); break; case 5: printf("请输入要查找元素的关键字:"); scanf("%d",&e); L1=Locate_LinkList(L,e); if(L1!=NULL)

printf("%d\n",L1->data); else

printf("找不到!\n"); break; case 6: printf("请输入要插入元素的内容:"); scanf("%d",&e); printf("请输入插入位置:"); scanf("%d",&i); if(Insert_LinkList(L,i,e)==OK)

printf("插入成功!\n"); else

printf("插入不成功!\n"); break; case 7: printf("请输入要删除元素的位置:"); scanf("%d",&i); if(Delete1_LinkList(L,i)==OK)

printf("成功删除!\n"); else

printf("未成功删除!\n"); break; case 8: printf("请输入要元素的内容:"); scanf("%d",&e); if(Delete2_LinkList(L,e)==OK)

printf("成功删除!\n"); else

云淡风清 http://gsqls.blog.163.com/

printf("未成功删除!\n"); break; case 9: printf("请输入要元素的内容:"); scanf("%d",&e); Delete3_LinkList(L,e); printf("成功删除!\n"); break; case 10: Delete4_LinkList(L); printf("成功删除!\n");

break; case 11: printf("请输入修改位置:"); scanf("%d",&i); printf("请输入元素的新内容:"); scanf("%d",&e); if(Modify_LinkList(L,i,e)==OK)

printf("修改成功!\n"); else

printf("修改不成功!\n"); break; case 12: Traverse_LinkList(L);

break; case 13: L1=Init_LinkList(); L2=Init_LinkList(); if((L1==NULL)||(L2==NULL))

printf("初始化不成功!\n"); else {

printf("请建立第一个链表:\n");

Create2_LinkList(L1);

printf("请建立第二个链表:\n");

Create2_LinkList(L2);

Sort_LinkList(L1);

Sort_LinkList(L2);

L=Merge_LinkList(L1,L2);

printf("合并后的结果如下:\n");

Traverse_LinkList(L); } break; case 14:

云淡风清 http://gsqls.blog.163.com/

}

} Sort_LinkList(L); break; case 15: Release_LinkList(L);

break; case 0: printf("谢谢使用,再见!\n"); break; default: printf("输入错误!\n"); break; } 2.4循环链表

循环链表(Circular Linked List):是一种头尾相接的链表,其特点是最后一个结点的指针域指向链表的头结点,整个链表的指针域链接成一个环,这样,从循环链表的任意一个结点出发都可以找到链表中的其它结点,使得表处理更加方便灵活。

下图是带头结点的单循环链表的示意图。

循环链表的操作:

对于带头结点的单循环链表,除链表的合并外,其它操作和单线性链表基本上一致,仅仅需要在单线性链表操作算法基础上做以下简单修改:

1、判断是否是空链表 head->next==head;

2、判断是否是表尾结点 p->next==head; 例:有m个人围成一圈,顺序排号。从第一个人开始报数,凡报到3的人退出圈子,问最后留下的那位是原来的第几号?

根据问题描述可知,该问题中m个人围坐在一起形成首尾相接的环,比较自然的一种思路是用循环链表模拟这个环。从第3个人开始出圈,相当于从链表中删除一个结点。该程序主要由三个模块组成:

1、建立循环单链表存放初始各人编号;

2、报数并按顺序输出出圈人的编号;

3、输出剩下的人的编号。具体步骤如下:

云淡风清 http://gsqls.blog.163.com/ 第一步:输入人员总数;

第二步:创建循环链表并向单链表中填入人员编号; 第三步:找第一个开始报数的人;

第四步:数到3让此人出圈(删除对应结点);

第五步:接着开始报数,重复第四步,直到圈中剩余一个为止; 第六步:输出剩下结点中的编号,即为最终所要求的编号。 程序源代码: #include "stdio.h" #include "stdlib.h" #define MAXN 100 //最大个数 struct Node { int data; struct Node *next; }; void main() { struct Node *head, *s, *q, *t; int n, m, count=0, i; do//输入总个数

{ printf("请输入总个数(1-%d):",MAXN); scanf("%d",&m); }while((mMAXN)); do//输入出圈时要数到的个数

{ printf("要数到的个数(1--%d):",m); scanf("%d",&n); }while((nm)); for(i=0;i

{ s=(struct Node *)malloc(sizeof(struct Node)); s->data=i+1; s->next=NULL; if(i==0) { head=s; q=head; } else

{ q->next=s; q=q->next; }

云淡风清 http://gsqls.blog.163.com/ } q->next=head;//形成圈

//以下代码输出原始状态

printf("原始状态:\n"); q=head; while(q->next!=head) { printf("%4d",q->data); q=q->next; } printf("%4d\n",q->data); q=head;//以下代码实现出圈

printf("出圈顺序:\n"); do { count++; if(count==n-1) { t=q->next; q->next=t->next; count=0; printf("%4d",t->data); free(t); } q=q->next; }while(q->next!=q); printf("\n剩下的是%4d\n",q->data); } 注意:此程序采用的是不带头结点的单链表,以免在循环链表中由于不存放有效数据的头结点的存在而影响计数。

2.5双向链表

双向链表是为了克服单链表的单向性的缺陷而引入的。单链表只能从头到尾单向访问各结点,对操作的限制极大。双向链表(Double Linked List)指构成链表的每个结点中设立两个指针域,一个指向其直接前趋结点,一个指向其直接后继结点,这样形成的链表中有两个方向不同的链,故称为双向链表。

和单链表类似,双向链表一般也增加一个不存放实际有效数据的头结点,从而使某些操作更方便。下面为带头结点的双向链表示意图:

云淡风清 http://gsqls.blog.163.com/ 将头结点和尾结点链接起来也能构成循环链表,并称之为双向循环链表。

2.5.1双向链表的结点及其类型定义

双向链表的结点的类型定义如下。 typedef struct Dulnode { ElemType data; struct Dulnode *prior,*next; }DulNode; 双向链表结构具有对称性,设p指向双向链表中的某一结点,则其对称性可用下式描述: (p->prior)->next=p=(p->next)->prior ; 结点p的存储位置存放在其直接前趋结点p->prior的直接后继指针域中,同时也存放在其直接后继结点p->next的直接前趋指针域中。

2.5.2双向链表的基本操作

1、双向链表结点的插入

将值为e的结点插入双向链表中。插入前后链表的变化如下图所示。

①若插入时仅仅指出直接前驱结点,钩链时必须注意先后次序是:“先右后左”,部分语句组如下: S=(DulNode *)malloc(sizeof(DulNode)); S->data=e; S->next=p->next;//先右 p->next->prior=S; //后左 p->next=S; //先右 S->prior=p; //后左

②若插入时同时指出直接前驱结点p和直接后继结点q,钩链时无须注意先后次序,部分语句组如下:

S=(DulNode *)malloc(sizeof(DulNode)); S->data=e; p->next=S; S->next=q; S->prior=p; q->prior=S;

2、双向链表结点的删除

设要删除的结点为p ,删除时可以不引入新的辅助指针变量,先直接断链,再释放结点。部分语句组如下:

p->prior->next=p->next; p->next->prior=p->prior; free(p);

云淡风清 http://gsqls.blog.163.com/ 注意:

与单链表的插入和删除操作不同的是,在双向链表中插入和删除必须同时修改两个方向上的指针域的指向。

2.6一元多项式的表示和相加 2.6.1一元多项式的表示

一元多项式如下:

p(x)=p0+p1x+p2x2+ „ +pnxn ,由n+1个系数唯一确定。则在计算机中可用线性表(p0 ,p1 ,p2 ,„ ,pn)表示。既然是线性表,就可以用顺序表和链表来实现。两种不同实现方式的元素类型定义如下:

1、顺序存储结构表示的类型 typedef struct { float

coef;

//系数部分

int

expn; //指数部分 } ElemType;

2、链式存储结构表示的类型 typedef struct ploy { float coef;

//系数部分

int

expn;

//指数部分

struct ploy *next; }Ploy; 2.6.2一元多项式的相加

不失一般性,设有两个一元多项式: P(x)=p0+p1x+p2x2+ „ +pnxn ,

Q(x)=q0+q1x+q2x2+ … +qmxm

(m

1、顺序存储表示的相加 线性表的定义: typedef struct { ElemType a[MAX_SIZE]; int

length; }Sqlist; 用顺序表示的相加非常简单,访问第i项可直接访问:L.a[i-1].coef,L.a[i-1].expn

2、链式存储表示的相加

当采用链式存储表示时,根据结点类型定义,凡是系数为0的项不在链表中出现,从而可以大大减少链表的长度。

云淡风清 http://gsqls.blog.163.com/ 一元多项式相加的实质是: 指数不同:是链表的合并。

指数相同:系数相加,和为0,去掉结点,和不为0,修改结点的系数域。 算法一:

就在原来两个多项式链表的基础上进行相加,相加后原来两个多项式链表不再存在,当然就不再允许对原来两个多项式进行其它操作了。

算法描述:

Ploy *add_ploy(ploy *La,ploy *Lb) //将以La ,Lb为头指针表示的一元多项式相加 { ploy *Lc,*pc,*pa,*pb,*ptr; float x; Lc=pc=La; pa=La->next; pb=Lb->next; while (pa!=NULL&&pb!=NULL) {

if(pa->expnexpn)//将pa所指的结点合并,pa指向下一个结点

{

pc->next=pa;

pc=pa;

pa=pa->next;

}

else

if(pa->expn>pb->expn)//将pb所指的结点合并,pb指向下一个结点

{

pc->next=pb;

pc=pb;

pb=pb->next;

}

else

{

x=pa->coef+pb->coef;

if(abs(x)

{

ptr=pa;

pa=pa->next;

free(ptr);

ptr=pb;

pb=pb->next;

free(ptr);

}

else//如果系数和不为0,修改其中一个结点的系数域,删除另一个结点

{

云淡风清 http://gsqls.blog.163.com/

pc->next=pa;

pa->coef=x;

pc=pa;

pa=pa->next;

ptr=pb;

pb=pb->next;free(pb);

}

} }//end of while if(pa==NULL)

pc->next=pb; else pc->next=pa; return (Lc); } 算法之二:

对两个多项式链表进行相加,生成一个新的相加后的结果多项式链表,原来两个多项式链表依然存在,不发生任何改变,如果要再对原来两个多项式进行其它操作也不影响。

算法描述:

Ploy *add_ploy(ploy *La,ploy *Lb) //将以La ,Lb为头指针表示的一元多项式相加,生成一个新的结果多项式 { ploy *Lc,*pc,*pa,*pb,*p; float x; Lc=pc=(ploy *)malloc(sizeof(ploy)); pa=La->next; pb=Lb->next; while (pa!=NULL&&pb!=NULL) {

if(pa->expnexpn)

{

p=(ploy *)malloc(sizeof(ploy));//生成一个新的结果结点并赋值

p->coef=pa->coef;

p->expn=pa->expn;

p->next=NULL;//生成的结点插入到结果链表的最后,pa指向下一个结点

pc->next=p;

pc=p;

pa=pa->next;

}

else

if(pa->expn>pb->expn)

{

p=(ploy *)malloc(sizeof(ploy));//生成一个新的结果结点并赋值

p->coef=pb->coef;p->expn=pb->expn;

p->next=NULL;

云淡风清 http://gsqls.blog.163.com/

pc->next=p;//生成的结点插入到结果链表的最后,pb指向下一个结点

pc=p;

pb=pb->next;

}

else

{

x=pa->coef+pb->coef;

if(abs(x)

{

pa=pa->next;

pb=pb->next;

}

else//若系数和不为0,生成的结点插入到结果链表的最后,pa, pb分别指向直接后继结点

{

p=(ploy *)malloc(sizeof(ploy));//生成一个新的结果结点并赋值

p->coef=x;p->expn=pb->expn;

p->next=NULL;

pc->next=p;

pc=p;

pa=pa->next;

pb=pb->next;

}

} }//end of while if(pb!=NULL)

while(pb!=NULL)

{

p=(ploy *)malloc(sizeof(ploy));//生成一个新的结果结点并赋值

p->coef=pb->coef;

p->expn=pb->expn;

p->next=NULL;

pc->next=p;

pc=p;

pb=pb->next;

} if(pa!=NULL)

while(pa!=NULL)

{

p=(ploy *)malloc(sizeof(ploy));//生成一个新的结果结点并赋值

p->coef=pb->coef;

p->expn=pa->expn;

p->next=NULL;

pc->next=p;

云淡风清 http://gsqls.blog.163.com/

}

pc=p;

pa=pa->next; } return (Lc);习题 二

1、简述下列术语:线性表,顺序表,链表。

2、何时选用顺序表,何时选用链表作为线性表的存储结构合适?各自的主要优缺点是什么?

3、在顺序表中插入和删除一个结点平均需要移动多少个结点?具体的移动次数取决于哪些因素?

4、链表所表示的元素是否有序?如有序,则有序性体现于何处?链表所表示的元素是否一定要在物理上是相邻的?有序表的有序性又如何理解?

5、设顺序表L是递增有序表,试写一算法,将x插入到L中并使L仍是递增有序表。

6、写一算法从一给定的向量A删除值在x到y(x≤y)之间的所有元素(注意:x和y是给定的参数,可以和表中的元素相同,也可以不同)。

7、设A和B是两个按元素值递增有序的单链表,写一算法将A和B归并为按按元素值递减有序的单链表C,试分析算法的时间复杂度。

推荐第4篇:数据结构实验教学

数据结构实验指导

说明:课内上机要求完成实验一到实验四的内容,并完成实验报告,实验报告在十七周星期三之前交,其他实验请大家课外抽时间完成。给出的示例程序供大家参考,大家实验的时候要自己动手编写程序,切不可完全照抄,每个实验具体的实验题目大家可以做示例的题目,也可以自己定一题目,只需用到该实验的知识点即可,编程语言大家可以选用自己熟悉的语言。

一.实验要求: 书写类C语言的算法,并将算法转变为程序实现。正确理解各种数据结构的逻辑特性和存储表示和基本操作的算法实现。针对问题的不同选择合适的数据结构,提高算法设计的能力和动手实验的技能。。 二.主要仪器设备:(所开实验的主要仪器设备)

硬件要求:在多媒体教室讲解及演示。为保证教学顺利进行,要求实验室提供PⅢ及以上的微机。

三、实验项目内容简介

为了达到实验目的,本课程安排了四个实习单元,训练的重点在于基本的数据结构,而不是强调面面俱到。各实习单元与教科书的各章只具有粗略的对应关系,一个实习题常常涉及到几部分教学内容。

1、线性表基本操作

(1) 熟悉线性表的基本运算在两种存储结构(顺序结构和链式结构)上的实现 (2)以线性表的各种操作(建立、插入、删除等)的实现为重点

(3) 通过本次实习帮助学生加深对高级语言C语言的使用(特别是函数参数、指针类型、链表的使用)。

2、栈、队列以及递归算法的设计

(1)掌握栈和队列这两种特殊的线性表,熟悉它们的特性,在实际问题背景下灵活运用它们 (2) 训练的要点是“栈”的观点及其典型用法;问题求解的状态表示及其递归算法;由递归程序到非递归程序的转化方法

3、树、图及其应用

(1) 树和图是两种非线性数据结构,广义表的实质是树结构,而稀疏矩阵的十字链表存储结构也是图的一种存储结构,故本单元是本课的实习重点。

(2) 要求学生熟悉各种存储结构的特性,以及如何应用树和图结构求解具体问题。 (3) 训练的要点是:递归算法的设计方法;表达式的求值技术;哈夫曼方法及其编译码技术;完整的应用系统的用户界面设计和操作定义方法;矩阵乘法的特殊操作顺序;路径遍历(树、图的遍历)技术。

4、查找和排序

本次实习旨在集中对几个专门的问题做较为深入的探讨和理解

重点在掌握各种内部排序算法、查找算法的思想和实现。学生在实习中体会查找和内部排序算法思想,理解开发高效算法的可能性和寻找、构造高效算法的方法。

四、主要参考书

1、《数据结构题集》(C语言版)实习题部分,清华大学出版社,1999.11

2、《数据结构习题与解析》(C语言篇),李春葆 编著,清华大学出版社,2000.1

3、宁正元《数据结构习题解析与上机实验指导》

水利水电出版社(2003年)

实验一

线性表的操作

一、实验目的

1.熟悉C语言的上机环境,掌握C语言的基本结构。 2.会定义线性表的顺序存储结构。(链式存储结构) 3.熟悉对顺序表(单链表)的一些基本操作。

二、实验要求

1.认真阅读和掌握本实验内容所给的全部程序。 2.保存和打印出程序运行结果,并结合程序进行分析。 注意事项

在做第一次“数据结构”课程实验之前,要在硬盘上建立好自己的工作目录,专门来存储你所做的实验程序及相关信息,以后每次做实验都采用这个目录。

三、实验内容

1、示例(以顺序表为示例,同学们也可以编程实现单链表的创建、查找、插入、删除等功能)

以输入整形数据为主,输入后按“?”结束输入。

程序所能表达到的功能为:实现顺序表的创建、查找、插入、删除等功能。 程序运行后,输入数据并执行。 #include \"stdio.h\" #include \"conio.h\" #define MaxSize 50 typedef char elemtype; typedef struct node { elemtype data[MaxSize]; int len; }lnode,*List; void init(List L){ L->len=0;} int length(List L) { return L->len;} elemtype getnode(List L,int pos) { if(posL->len) printf(\"error\"); else return L->data[pos-1]; } int locate(List L,elemtype x) { int i=0; while(ilen && L->data[i]!=x) i++; if(i==L->len) return -1; else return(i+1); } void insert(List L,int pos,elemtype x) { int j; if(posL->len+1) printf(\"insert error\\n\"); else { L->len++; for(j=L->len;j>=pos;j--) L->data[j]=L->data[j-1]; L->data[pos-1]=x; }; } void delnode(List L,int pos) { int j; if(posL->len)printf(\"del error\\n\"); else { for(j=pos;jlen;j++) L->data[j-1]=L->data[j]; L->len--;} } void print(List L) { int i; for(i=1;ilen;i++) printf(\"%c->\",L->data[i-1]); printf(\"%c\",L->data[L->len-1]); } main() { int i=1,n; lnode L; char ch,x; init(&L); printf(\"\\n\\n\\n*******************************顺序表演示程序***********\\n\"); printf(\"请输入你想建立的顺序表的元素,以?结束:\"); ch=getchar(); while(ch!=\'?\') {insert(&L,i,ch); i++; ch=getchar(); }; printf(\"你建立的顺序表为:\"); print(&L); printf(\"\\n顺序表的长度为:%d\",L.len); printf(\"\\n输入你想查找的元素:\"); fflush(stdin); scanf(\"%c\",&x); printf(\"你查找的元素为%c序位为%d\",x,locate(&L,x)); printf(\"\\n输入你想查找的元素序位:\"); scanf(\"%d\",&n); printf(\"\\n你查找的元素为:%c\",getnode(&L,n)); printf(\"\\n输入你想插入的元素以及序位:\"); fflush(stdin); scanf(\"%c,%d\",&x,&n); insert(&L,n,x); printf(\"\\n插入后顺序表为:\"); print(&L); fflush(stdin); printf(\"\\n请输入你想删除的元素序位:\"); scanf(\"%d\",&n); delnode(&L,n); printf(\"\\n删除后的顺序表为:\"); print(&L); getch(); }

四、测试结果

运行程序,屏幕显示:“请输入你想建立的顺序表的元素,以?结束:” 输入:54381 你建立的顺序表为:5—>4—>3—>8—>1 顺序表的长度为:5 输入你想查找的元素:4 你查找的元素为4序位为2 输入你想查找的元素序位:4 你查找的元素为:8

输入你想插入的元素以及序位:\":6,3 插入后顺序表为:5—>4—>6—>3—>8—>1 请输入你想删除的元素序位:5 删除后的顺序表为:5—>4—>6—>3—>1

实验二 二叉树的操作 一.实验目的

理解并熟悉掌握创建二叉树和实现二叉树的三种遍历 二.实验内容

创建二叉树和实现二叉树的三种遍历

根据提示输入字符型数据创建二叉树,输入值为所有字符型数据 输出为遍历后的每个结点的值的顺序

创建二叉树并能实现二叉树的先序、中序、后序遍历 如果输入数据为:a b c 输出结果为:a b c

b a c

b c a

程序流程:main()clrscr()createtree()preorder()inorder()postorder 源程序

#include \"stdlib.h\" struct tnode {char data; struct tnode*lchild; struct tnode*rchild; }; struct tnode tree;

void createtree(struct tnode*t) {struct tnode*p=t;

char check; if(p->lchild==NULL||p->rchild==NULL) /*判断左右子树是否为空*/

{printf(\"please enter the data:\");

scanf(\"%c\",&(p->data));

getchar();

}

/*输入根结点数据*/

/*创建函数*/

/*定义二叉树指针*/

/*引入头文件*/ /*定义二叉树存储结构*/

/*把二叉树指针给p*/ if(p->lchild==NULL)

{printf(\"%c leftchild is null.Add? y/n\\n\",p->data); /*左子树空,询问是否创建*/

scanf(\"%c\",&check);

getchar();

if(check==\'y\')

{struct tnode*q=(struct tnode*)malloc(sizeof(struct tnode)); /*开辟空间*/

q->lchild=NULL;

q->rchild=NULL;

p->lchild=q;

createtree(q);

}

} if(p->rchild==NULL)

{printf(\"%c rightchild is NULL.Add? y/n\\n\",p->data); /*右子树空,询问是否创建*/

scanf(\"%c\",&check);

getchar();

if(check==\'y\')

{struct tnode*q=(struct tnode*)malloc(sizeof(struct tnode)); /*开辟空间*/

q->lchild=NULL;

q->rchild=NULL;

p->rchild=q;

createtree(q);

}

} }

void preorder(struct tnode*t) {if(t)

{printf(\"%c \",t->data);

/*输出根结点数据*/

/*先序遍历函数*/

/*连到二叉树上*/

preorder(t->lchild);

preorder(t->rchild);

} }

void inorder(struct tnode*t) {if(t)

{inorder(t->lchild);

printf(\"%c \",t->data);

inorder(t->rchild);

} } void postorder(struct tnode*t) /*后序遍历函数*/ {if(t)

{

postorder(t->lchild);

postorder(t->rchild);

printf(\"%c \",t->data);

} }

void main() { clrscr();

/*清屏函数*/

/*左子树*/ /*右子树*/ /*创建二叉树*/

/*中序遍历函数*/ tree.lchild=NULL; tree.rchild=NULL; createtree(&tree);

preorder(&tree);

printf(\"\\n\"); inorder(&tree);

/*先序遍历*/

/*中序遍历*/ printf(\"\\n\"); postorder(&tree); }

三.使用说明

程序运行:

先输入根结点数据,例如:a 输入y或n判断是否创建左子树。输入y然后输入左子树数据 输入y或n判断是否创建右子树。输入y然后输入右子树数据 按回车可查看遍历结果并退出程序。

四.测试结果

运行程序,屏幕提示:

please enter the data:a

/*首先输入根结点,为a*/ a leftchild is null.add?y/n

/*询问是否输入a结点的左结点*/ y

/*输入*/ please enter the data:b

/*输入结点a的左结点,为b*/ b leftchild is null.add?y/n

/*询问是否输入b结点的左结点*/ n

/*不输入*/ b rightchild is null.add?y/n

/*询问是否输入b结点的右结点*/ n

/*不输入*/ a rightchild is null.add?y/n

/*询问是否输入a结点的右结点*/ y

/*输入*/ please enter the data:c

/*输入结点a的右结点,为c*/ c leftchild is null.add?y/n

/*询问是否输入c结点的左结点*/ n

/*不输入*/ c rightchild is null.add?y/n

/*询问是否输入c结点的右结点*/ n

/*不输入*/ 程序退出,显示结果应为:

a b c

/*先序*/

/*后序遍历*/

b a c

/*中序*/

b c a

/*后序*/

实验三

图的遍历操作

一.实验目的:

该实验主要完成对图的创建,并实现图的深度优先遍历和广度优先遍历 二.实验内容:

所输入的数据要为整形数据

输出的形式为:每按一次回车,遍历一个结点

能创建最大结点树为30的任意图,实现对无向图的两种遍历 程序流程:

main()clrscr()visited()DFS()visited()BFS() 源程序: #include #define maxvex 30 struct edgenode {int adjvex; char info; struct edgenode*next; }; struct vexnode {char data; struct edgenode*link; }; typedef struct vexnode adjlist[maxvex]; /*自定义adjlist为结构体数组类型*/ adjlist tu1;

void creategraph(adjlist g,int n) {int e,i,s,d;

/*图创建函数*/

/*定义存储边、点的变量*/ /*定义边的结构体指针*/ /*显示提示输入点,边*/

/*定义结构体数组变量tu1*/

/*定义点的结构体*/

/*引用两个头文件*/ /*定义MAXVEX=30*/

/*定义边的结构体*/ struct edgenode*p,*q;

printf(\"the point(n) and edge(e):\"); scanf(\"%d,%d\",&n,&e); for(i=1;i

{getchar();

/*接收点、边存入n,e中*/

/*提示输入结点信息*/ /*存储信息*/ /*最后指针为空*/

printf(\"\\tthe %d information:\",i);

scanf(\"%c\",&g[i].data);

g[i].link=NULL;

}

for(i=1;i

{printf(\"\\nthe%d edges=>\\n\\t :\",i);

scanf(\"%d,%d\",&s,&d);

/*提示输入边信息*/ /*接收边的信息*/

p=(struct edgenode*)malloc(sizeof(struct edgenode));

q=(struct edgenode*)malloc(sizeof(struct edgenode)); /*开辟两个存储边的空间*/

p->adjvex=d;

p->info=g[d].data;

q->adjvex=s;

q->info=g[s].data;

p->next=g[s].link;

g[s].link=p;

q->next=g[d].link;

g[d].link=q;

} }

int visited[maxvex];

/*定义访问数组*/

/*q和s的link指针连接起来*/ /*完成一个边的创建*/

/*p和s的link指针连接起来*/

/*把另一个点存储下来*/

/*把其中一个点存储下来*/ void dfs(adjlist adj,int v) {int i; struct edgenode*p; visited[v]=1;

/*深度优先遍历函数*/

/*定义边指针*/

/*把开始遍历的点在访问数组中标识*/

/*输出正访问的点*/ printf(\"now is at point %d\",v);

p=adj[v].link; printf(\"the data is %c \\n\",adj[v].data); getch(); while(p)

{if(visited[p->adjvex]==0)

dfs(adj,p->adjvex);

p=p->next;

} }

int quene[maxvex]; void bfs(adjlist adj,int vi) {int m=maxvex;

/*输出点的信息*/

/*没有访问的再调用DFS函数*/

/*访问过的判断下一个*/

/*广度优先遍历函数*/ /*定义一个队列*/ int front=0,rear=1,v; struct edgenode*p; visited[vi]=1;

/*定义边指针*/

/*开始访问的点标识一下*/

/*输出正访问的点*/ printf(\"now visit the point:%d\\n\",vi);

getch();quene[rear]=vi; while(front!=rear)

{front=(front+1)%m;

v=quene[front];

p=adj[v].link;

while(p)

{if(visited[p->adjvex]==0)

{visited[p->adjvex]=1;

/*把访问过的点放入数组中*/

/*判断p->adjvex点是否访问过*/ /*访问没有访问过的结点*/ printf(\"now visit the point:%d\\n\",p->adjvex); /*输出正访问的结点*/ getch();

rear=(rear+1)%m;

quene[rear]=p->adjvex;

}

p=p->next;

/*指向下一个*/

/*放入数组中*/

}

} }

void main() {int i;clrscr(); creategraph(tu1,0); for(i=1;i

visited[i]=0;

dfs(tu1,1);

getch();

/*访问数组初始化*/

/*调用DFS*/

/*创建图*/

/*等待输入*/

for(i=1;i

visited[i]=0; bfs(tu1,1);

} 三.使用说明:

根据屏幕上的英文提示先输入结点的个数和边数。然后输入各结点存储的信息,再输入定义的边,形成图。最后分别按照DFS深度优先遍历和BFS广度优先遍历实现对图的遍历。 四.测试结果: 运行程序,屏幕提示:

the point(n) and edge(e):4,3 /*输入顶点和边的数目*/ the 1 information:a

/*各个顶点的信息*/ the 2 information:b the 3 information:c the 4 information:d the 1 edges=>

/*各个边的连接情况*/ :1,2 the 2 edges=>:1,3 the 3 edges=>

/*调用BFS*/ :3,4

now is at point 1 the data is a /*深度优先遍历结果*/

now is at point 3 the data is c now is at point 4 the data is d now is at point 2 the data is b now visit the point:1

/*广度优先遍历结果*/ now visit the point:3 now visit the point:2 now visit the point:4

a b c d 实验四

栈的基本操作

一、实验目的:

1.熟练掌握栈的结构,以及这种数据结构的特点;

2. 能够在两种存储结构上实现栈的基本运算,特别注意栈满和栈空的判断条件及描述方法;

二、实验内容: 计算表达式的值 【问题描述】

计算用运算符后缀法表示的表达式的值。后缀表达式也称逆波兰表达式,比中缀表达式计算起来更方便简单些,中缀表达式要计算就存在着括号的匹配问题,所以在计算表达式值时一般都是先转换成后缀表达式,再用后缀法计算表达式的值。如:表达式(a+b*c)/d-e用后缀法表示应为abc*+d/e-。只考虑四则算术运算,且假设输入的操作数均为1位十进制数(0—9),并且输入的后缀形式表达式不含语法错误。 【数据描述】 #define add 43 /*运算符加号„+‟的ASCII码*/ #define subs 45 /*运算符减号„-‟的ASCII码*/ #define mult 42 #define div 47 /*运算符乘号„*‟的ASCII码*/ /*运算符除号„/‟的ASCII码*/ #define MAXSIZE 100 typedef struct{ { int stkdata[MAXSIZE];//用数组来表示栈空间,定义长度为MAXSIZE的栈

int top;

}STKzone; typedef STKzone *STK; typedef enum{true=1,false=0} bool; typedef enum{ok,error} status;

【C源程序】 #include #define add 43

/*运算符加号„+‟的ASCII码*/ //栈顶指针 #define subs 45

/*运算符减号„-‟的ASCII码*/ #define mult 42

/*运算符乘号„*‟的ASCII码*/ #define div 47

/*运算符除号„/‟的ASCII码*/ #define MAXSIZE 100 typedef struct { int stkdata[MAXSIZE];/*用数组来表示栈空间,定义长度为MAXSIZE的堆栈*/

int top; /*栈顶*/ }STKzone; typedef STKzone *STK; typedef enum{true=1,false=0} bool; typedef enum{ok,error} status; STKzone expSTKzone; STK expSTK; STK initSTK(STKzone *stack_zone){

/*执行栈初始化,建栈指针*/

STK p;

p=stack_zone;

p->top=0; } status push(int *term,STK pstk){ /*将一结构型数据送入栈中*/ if(pstk->top==MAXSIZE)

return error; /*栈满,进栈失败*/ pstk->stkdata[pstk->top] =*term; (pstk->top)++;/*栈顶指针移动*/ return ok; }/*push*/ bool emptySTK(STK pstk){ /*判断栈是否为空栈*/ return(pstk->top==0); } status pop(int *pdata, STK pstk){

/*从栈中取出一结构型数据*/ if(emptySTK(pstk))

return error; (pstk->top)--;/*退栈*/ *pdata =pstk->stkdata[pstk->top]; return ok; } void synerror() { printf(\"\\n表达式语法错!\"); exit(); } int eval(char tag,int a1,int a2) { switch(tag)

{ case add:return(a1+a2); case subs:return(a1-a2); case mult:return(a1*a2); case div:return(a1/a2); } } main() { char c;

int opd1,opd2,temp,c1;

expSTK=initSTK(&expSTKzone);

printf(\"\\n后置表达式: \");

while((c=getchar())!=\'\\n\')

{ if(c== \' \') continue; if((c>47)&&(c

{ putchar(c);

/*判断是否是0—9的字符*/ c1=c-48;

/*把输入的字符型数字转换成数字*/

if(push(&c1,expSTK)==error)/*运算分量进栈*/

{ printf(\"\\n表达式太长\\n\");

exit();} } else if((c==add)||(c==subs)||(c==mult)||(c==div))

{ putchar(c); if(pop(&opd1,expSTK)==error) /*将运算量1出栈*/ synerror();

if(pop(&opd2,expSTK)==error) /*将运算量2出栈*/ synerror();

}

else synerror();/*出现非法字符*/ }/*while*/ if(pop(&opd1,expSTK)==error) synerror(); if(!(emptySTK(expSTK))) synerror(); printf(“=%-3d\\n”,opd1); }/*main_end*/ 【测试数据】 输入: 23+↙

输出: =5

(即求2+3的结果) 输入: 145*+3/3-↙

输出: 4 (即求(1+4*5)/3-3的结果) 【说明】

本算法中对后置法表示的表达式求值按如下规则进行:自左向右扫描,每遇到一个`n+1元组(opd1,opd2,…,opdn,opr)(其中opd为操作数,opr为n元运算符),就计算一次opr(opd1,opd2,…,opdn)的值,其结果取代原来表达式中n+1元组的位置,再从表达式开头重复上述过程,直到表达式中不含运算符为止。 temp=eval(c,opd2,opd1);/*计算得到结果*/ push(&temp,expSTK);/*将运算结果进栈*/ 【实验题】

1.假设一个算术表达式中包含零对到多对圆括弧,括弧对之间允许嵌套但不允许交叉,编写一个算法并上机实现:判断输入的表达式是否正确配对。Status correct(string expre);//括弧配对正确,返回ok,否则返回error 2.3. 用栈实现一般表达式(即中缀表达式)到后缀表达式的转换。 数制转换。

实验五 数据查找

一.实验目的:

理解各种查找的思想,实现对数据的查找。例如用:直接查找法和折半查找法。 二.实验内容:

任意输入10个整形数据,然后再输入一个数据进行查找。 该程序能对输入的数据进行查找,然后把数据所在的位置输出。 例如:输入10个数据:12 3 4 5 6 7 8 9 1 2

输入查找数据:5 输出为:the 5 is at 4 position 源程序:

#include #include void seqsearch(int*,int); void binsearch(int*,int); void bubblesort(int*,int);

void menu() { printf(\" 1.seqsearch()\\n\"); printf(\" 2.binsearch()\\n\"); printf(\" 3.exit()\\n\"); printf(\"please select the method:\"); }

void main() {int i,j=1; int ch; int a[10];

/*声明插入查找函数*/ /*声明折半查找函数*/

/*声明起泡排序函数*/

/*引入头文件*/ clrscr(); printf(\"please input 10 data:\"); for(i=0;i

scanf(\"%d\",&(a[i]));

menu(); while(j)

/*接收输入*/

/*提示输入10个数据*/

/*显示菜单*/ /*循环一次*/ {scanf(\"%d\",&ch);

switch(ch)

{case 1:seqsearch(a,10);break;

case 2:binsearch(a,10);break;

case 3:j=0;break;

default:break;

}

printf(\"\\n\");

menu();

} }

void seqsearch(int*r,int n)

{int i=0,data; printf(\"please input find data:\");

scanf(\"%d\",&data);

while(r[i]!=data)

i++; if(i>n)

printf(\"the data is not found\");

else printf(\"the %d position is %d\",data,i+1); getch(); }

/*选择执行程序*/

/*直接查找函数*/

/*提示输入查找数据*/ /*接收数据*/

/*循环查找*/

/*输出数据没有找到*/

/*如果找到,输出位置*/

void binsearch(int *r,int n)

{int j,data,low=0,high=n,mid,find=0; bubblesort(r,n);

for(j=0;j

printf(\"%d \",r[j]);

printf(\"please input find data:\");

scanf(\"%d\",&data); while(low

{mid=(low+high)/2;

if(data

high=mid-1;

else if(data>r[mid])

low=mid+1; else find=1;

} if(!find)

printf(\"the data is not found!\\n\");

else printf(\"the data position is %d\",mid+1); getch(); }

void bubblesort(int *r,int n)

{int i,j,k,temp; k=n-1; for(j=0;j

{for(i=0;i

{if(r[i]>r[i+1])

{temp=r[i];

r[i]=r[i+1];

r[i+1]=temp;

/*折半查找函数*/

/*起泡法排序*/

/*排序后输出*/

/*提示输入查找数据*/

/*循环查找*/

/*置mid指针*/

/*判断数据大小,移动指针*/

/*显示数据没有找到*/

/*输出数据位置*/

/*起泡排序函数*/

/*比较大小*/

/*交换数据的位置*/

}

}

k=k-1;

} }

三.使用说明:

按提示输入10个任意的整形数据;输入要查找的数据;

可以看到所要查找的数据的位置。

四.测试结果: 运行程序,屏幕提示

please input 10 data:12 3 4 5 6 seqsearch()

binsearch()

exit please select the method:1

please input find data:5

the 5 is at 4 position

please select the method:2 please input find data:5 the 5 is at 4 position

7 8 9

2 /*输入10个数据*/ /*顺序查找*/ /*折半查找*/

/*选择顺序查找*/

/*输入要查找的数据*/

/*输出正确结果,并返回提示*/

实验六 哈希表设计

一.实验目的:

熟练掌握哈希表的构造方法,深刻理解哈希表与其他结构表的实质性差别。 二.实验内容:

程序的功能是对一批关键字集合采用除留余数法和线性探测再散列的方法解决冲突来建立相应的哈希表和完成查找过程及平均查找长度的计算。 【问题描述】

研究哈希(HAXI)表查找技术的两个重要问题是:构造HAXI函数和处理冲突。现在要求针对某个数据集合中的关键字设计一个哈希表(选择合适的哈希函数和处理冲突的方法),完成HAXI表的建立、查找,并计算HAXI表查找成功的平均查找长度。HAXI函数的构造方法有多种,其中除留余数法是一种最简单和最常用的方法。

考虑具体问题的关键字集合,如{19,14,23,1,68,20,84,27,55,11,10,79}这样一组数据和给定的哈希表长m 或哈希表的装填因子a,选用除留余数法和线性探测再散列技术解决冲突所形成的哈希表以及该哈希表在查找成功时的平均查找长度ASL。

【数据描述】

HAXI表是根据设定的HAXI函数和处理冲突的方法将一组关键字映射到一个有限的连续的地址区间上,并以关键字在地址区间的“象”作为记录在表中的存储位置。因此我们可以采用动态分配的顺序存储结构表示HAXI表。

typedef struct {

KeyType key ; }ElemType;

//元素类型的定义

ElemType *HAXI;//动态分配的哈希表的首地址

【算法描述】

1、选择合适的哈希函数H( key)=key % p(P为小于或等于HAXI 表长的最大质数);

2、计算各个关键字的直接哈希函数值;

3、根据处理冲突的方法建立哈希表,并输出;

4、在哈希表中进行查找,输出查找的结果,以及所需和记录关键字比较的次数,并计算和输出在等概率情况下查找成功的平均查找长度。

三、源程序 #include #include #define NULL 0 typedef int KeyType; typedef struct {

KeyType key ; }ElemType; int haxi(KeyType key,int m){ /*根据哈希表长m, 构造除留余数法的哈希函数haxi*/

int i,p,flag;

for (p=m ; p>=2 ; p--)

/*p为不超过m的最大素数*/

{ for (i=2,flag=1;i

if (p %i==0) flag=0;

if (flag==1) break;

} return key%p;

/*哈希函数*/ }

void inputdata(ElemType **ST,int n ){ /*从键盘输入n个数据,存入数据表ST(采用动态分配的数组空间)*/

KeyType key;

int i;

(*ST)=(ElemType*)malloc(n*sizeof(ElemType));

printf(\"\\nPlease input %d data:\",n);

for (i=0;i

scanf(\"%d\",&((*ST)[i].key)); }

void createhaxi(ElemType **HAXI,ElemType *ST,int n,int m){

/*根据数据表ST,构造哈希表HAXI*,n,m分别为数据集合ST和哈希表的长度*/ int i,j;

(*HAXI)=(ElemType*)malloc(m*sizeof(ElemType));

for (i=0;i

for (i=0;i

j=haxi(ST[i].key,m);

/*获得直接哈希地址*/

while ((*HAXI)[j].key!=NULL) j=(j+1)%m;/*用线性探测再散列技术确定存放位置*/

(*HAXI)[j].key=ST[i].key;

/*将元素存入哈希表的相应位置*/

} }

int search(ElemType *HAXI,KeyType key,int m,int *time){

/*在表长为m的哈希表中查找关键字等于key的元素,并用 time记录比较次数,

若查找成功,函数返回值为其在哈希表中的位置,否则返回-1*/ int i;

*time=1;

i=haxi(key,m);

while (HAXI[i].key!=0 && HAXI[i].key!=key) {i++; ++*time;}

if (HAXI[i].key==0) return -1;

else return i; } main(){

ElemType *ST,*HAXI;

KeyType key;

int i,n,m,stime,time;

char ch;

printf(\"\\nPlease input n && m(n

/*输入关键字集合元素个数和HAXI表长*/

scanf(\"%d%d\",&n,&m);

inputdata(&ST,n);

/*调用函数,输入n个数据*/

createhaxi(&HAXI,ST,n,m);

/*建立哈希表*/ /*输出已建立的哈希表*/

printf(\"\\nThe haxi Table is\\n\");

for (i=0;i

printf(\"\\n\");

for (i=0;i

/*哈希表的查找,可进行多次查找*/ do {

printf(\"\\nInput the key you want to search:\");

scanf(\"%d\",&key);

i=search(HAXI,key,m,&time);

if (i!=-1) {printf(\"\\nSucce,the position is %d \",i);/*查找成功*/

printf(\"\\nThe time of compare is %d\",time);

}

else{ printf(\"\\nUnsucce\");

/*查找失败*/

printf(\"\\nThe time of compare is %d\",time);

}

printf(\"\\nContinue(y/n):\\n\");

/*是否继续查找yes or no*/

ch=getch();

} while (ch==\'y\' || ch==\'Y\') ;

/*计算表在等概率情况下的平均查找长度,并输出*/

for (stime=0,i=0;i

search(HAXI,ST[i].key,m,&time);

stime+=time;

};

printf(\"\\nThe Average Search Length is%5.2f\",(float)stime/n);

ch=getch(); }

四、测试数据

按运行提示输入数据(关键字集合)ST,建立HAXI表,然后进行多次查找。 Please input n && m(n

0 1

7 14

68 27 55 19 20 84 Input the key you want to search:27 Succe,the position is 4 The time of compare is 4; Continue(y/n):y

Input the key you want to search:68 Succe,the position is 3 The time of compare is 1; Continue(y/n):n

The Average Search Length is 2.5

10 79 23

11 12

10 实验七 排序 一.实验目的:

理解各种排序的思想,实现对数据的排序。例如用:起泡排序和插入排序。 二.实验内容:

按提示输入10个整形数据。 每个数据中间一空格输出

程序达到的功能要求对输入的10个数据进行排序 例如:输入2 4 3 5 6 8 9 11 15 0

输出 0 2 3 4 5 6 8 9 11 15 源文件: #include #include void bubblesort(int[],int); void insertsort(int[],int);

void menu() {printf(\"

1.bubblesort()\\n\"); printf(\"

2.insertsort()\\n\"); printf(\"please select the method:\"); }

void main() {int i,j=1; int ch; int a[10]; clrscr(); printf(\"please input 10 data:\"); for(i=0;i

scanf(\"%d\",&a[i]);

/*显示提示输入10个数据*/ menu();

while(j--) {ch=getchar();

ch=getchar();

switch(ch)

{case\'1\':bubblesort(a,10);break;

case\'2\':insertsort(a,10);break;

} } for(i=0;i

printf(\"%d \",a[i]);

} void insertsort(int r[],int n)

{int i,j,temp1,temp2;

for(i=1;i

{temp1=r[i];j=i-1;

while(temp1=0)

{temp2=r[j+1];

r[j+1]=r[j];

r[j]=temp2;j--;

}

r[j+1]=temp1;

} }

void bubblesort(int r[],int n)

{int i,j,change,temp; for(i=n-1,change=1;i>=0&&change;--i)

{change=0;

for(j=0;j

/*显示菜单*/

/*选择排序方法*/

/*输出排序结果*/

/*插入排序函数定义*/ /*定义控制循环及中间变量*/

/*数据交换位置*/

/*起泡排序法函数定义*/

{if(r[j]>r[j+1])

/*数据交换位置*/

{temp=r[j+1]; r[j+1]=r[j]; r[j]=temp; change=1; }

}

} }

三.使用说明:

按提示输入10个整形数据 在菜单中选择排序的方法 查看排序结果

四.测试结果:

运行程序,屏幕提示

please input 10 data: 2 4 3 5 bubblesort() insertsort()

please select the method:1

0 2 3 4 5 6 8 9

please select the method:2

0 2 3 4 5 6 8 9

6 8 9 11 15 11 15 11 15 0

推荐第5篇:数据结构课程设计

数据结构课程设计

1.赫夫曼编码器

设计一个利用赫夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。 要求:

1) 将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中)

2) 初始化:键盘输入字符集大小

26、26个字符和26个权值(统计一篇英文文章中26个字母),建立哈夫曼树;

3) 编码:利用建好的哈夫曼树生成哈夫曼编码;

4) 输出编码(首先实现屏幕输出,然后实现文件输出); 5) 界面优化设计。

代码如下:

#include #include #include #include #define N 200

typedef struct HTNode

//结构体 { int Weight;

char ch; int Parent,Lchild,Rchild; }HTNode; typedef char * * HCode;

void Save(int n,HTNode *HT)

//把权值保存到文件 {

FILE * fp;

int i;

if((fp=fopen(\"data.txt\",\"wb\"))==NULL)

{

printf(\"cannot open file\\n\");

return;

}

for(i=0;i

if(fwrite(&HT[i].Weight,sizeof(struct HTNode),1,fp)!=1)

printf(\"file write error\\n\");

fclose(fp);

system(\"cls\");

printf(\"保存成功!\");

}

void Create_H(int n,int m,HTNode *HT)

//建立赫夫曼树,进行编码 {

int w,k,j; char c; for(k=1;k

if(k

{

printf(\"\\n请输入权值和字符(用空格隔开): \");

scanf(\"%d\",&w);

scanf(\" %c\",&c); HT[k].ch=c;

HT[k].Weight=w;

}

else HT[k].Weight=0;

HT[k].Parent=HT[k].Lchild=HT[k].Rchild=0; }

int p1,p2,w1,w2;

for(k=n+1;k

p1=0;p2=0;

w1=32767;w2=32767;

for(j=1;j

{

if(HT[j].Parent==0)

{

if(HT[j].Weight

{

w2=w1;p2=p1;

w1=HT[j].Weight;

p1=j;

}

else if(HT[j].Weight

{

w2=HT[j].Weight;

p2=j;

}

}

} HT[k].Lchild=p1;HT[k].Rchild=p2; HT[k].Weight=HT[p1].Weight+HT[p2].Weight;

HT[p1].Parent=k;HT[p2].Parent=k;

} printf(\"输入成功!\"); }

void Coding_H(int n,HTNode *HT)

//对结点进行译码 { int k,sp,fp,p; char *cd; HCode HC;

HC=(HCode)malloc((n+1)*sizeof(char *));

cd=(char *)malloc(n*sizeof(char)); cd[n-1]=\'\\0\';

printf(\"************************\\n\"); printf(\"Char Coding\\n\");

for(k=1;k

{

sp=n-1;p=k;fp=HT[k].Parent;

for(;fp!=0;p=fp,fp=HT[fp].Parent)

if(HT[fp].Lchild==p)

cd[--sp]=\'0\';

else

cd[--sp]=\'1\';

HC[k]=(char *)malloc((n-sp)*sizeof(char));

strcpy(HC[k],&cd[sp]);

printf(\"%c

%s\\n\",HT[k].ch,HC[k]);

}

printf(\"************************\\n\"); free(cd) ; } void Read(int n,HTNode *HT)

//从文件中读出数据 {

int i; FILE * fp; if((fp=fopen(\"data.txt\",\"rb\"))==NULL) {

printf(\"cannot open file\\n\");

exit(0); } for(i=0;i

fread(&HT[i].Weight,sizeof(struct HTNode),1,fp); // printf(\"%d \\n\",HT[i].Weight);

} Coding_H(n,HT);

fclose(fp); }

void Print_H(int m,HTNode *HT)

//输出赫夫曼造树过程 { int k; printf(\"************************\\n\"); printf(\"Num Weight

Par LCh RCh \\n\"); for(k=1;k

printf(\"%d \",k);

printf(\"

%d\",HT[k].Weight);

printf(\"

%d\",HT[k].Parent);

printf(\"

%d\",HT[k].Lchild);

printf(\"

%d\\n\",HT[k].Rchild);

} printf(\"************************\\n\"); }

void Decode(int m,HTNode *HT)

//对输入的电文进行译码 { int i,j=0; char a[10]; char endflag=\'2\'; i=m; printf(\"输入发送的编码,以‘2’结束:\"); scanf(\"%s\",&a); printf(\"译码后的字符:\"); while(a[j]!=\'2\') {

if(a[j]==\'0\')

i=HT[i].Lchild;

else i=HT[i].Rchild;

if(HT[i].Lchild==0)

//HT[i]是叶结点

{

printf(\"%c\",HT[i].ch);

i=m;

//回到根结点

}

j++; } printf(\"\\n\"); if(HT[i].Lchild!=0&&a[j]!=\'2\')

printf(\"ERROR\"); }

int main()

//主函数 { int n,m,c; HTNode HT[N]; do {

system(\"color 2f\");

//运行环境背景颜色.

printf(\"\\n\\n\\t\\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n\\t\\t\");

printf(\"\\n\\t\\t\\t 赫夫曼编译码系统 \\t\\t\\t\");

printf(\"\\n\\n\\t\\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n\\t\\t\");

printf(\"\\n\\t\\t\\t1.输入权值、字母\\n\\t\\t\\t2.把数据写入文件\\n\\t\\t\\t3.输出赫夫曼编码表\\n\\t\\t\\t\");

printf(\"4.输出赫夫曼译码表\\n\\t\\t\\t5.输入编码并译码.\\n\\t\\t\\t6.从文件中读出数据\\n\\t\\t\\t7.退出\");

printf(\"\\n\\n\\t\\t\\t请选择:\");

scanf(\"%d\",&c);

switch(c)

{

case 1:system(\"cls\");printf(\"输入多少结点:\");

scanf(\"%d\",&n);m=2*n-1;Create_H(n,m,HT);break;

case 2:system(\"cls\");Save(n,HT);break;

case 3:system(\"cls\");Print_H(m,HT);break;

case 4:system(\"cls\");Coding_H(n,HT);break;

case 5:system(\"cls\");Decode(m,HT);break;

case 6:system(\"cls\");Read(n,HT);break;

case 7:system(\"cls\");exit(0);

}

}while(1); return 0; }

运行界面如下:

2.学生成绩管理(链表实现) 要求:

实现如下功能:增加、查找、删除、输出、退出。

代码如下:

#include #include #include typedef struct score

//定义成绩信息结构体 {

char Number[20]; char Name[20]; char Chinese[20]; char English[20]; char Math[20]; }score; typedef struct node_score

//定义成绩信息链表结点,包括数据域和指针域 {

score data; struct node_score *next; }node_score,*p_node_score; p_node_score headScore;//定义链表的头指针为全局变量 void PrintScore(score s) //输出信息函数 { printf(\" %10s\",s.Number); printf(\" |

%-6s\",s.Name); printf(\"

|

%-3s\",s.Chinese); printf(\"

|

%-3s\",s.English);

printf(\" |

%-3s\\n\",s.Math); } void View()//输出函数 {

p_node_score pNodeScore;

pNodeScore=headScore; printf(\"

学号

|

姓名

| 语文成绩

| 英语成绩| 高数成绩\\n\"); while(pNodeScore != NULL) {

PrintScore(pNodeScore->data);//输出学生信息和成绩信息

pNodeScore=pNodeScore->next; } } void Add() {

p_node_score pNodeScore; // 定义一个节点

pNodeScore=(p_node_score)malloc(sizeof(node_score));//为节点分配存储空间

printf(\"请输入学号:\"); scanf(\"%s\",pNodeScore->data.Number); printf(\"请输入姓名:\"); scanf(\"%s\",pNodeScore->data.Name); printf(\"请输入语文成绩:\"); scanf(\"%s\",pNodeScore->data.Chinese); printf(\"请输入英语成绩:\"); scanf(\"%s\",pNodeScore->data.English); printf(\"请输入高数成绩:\"); scanf(\"%s\",pNodeScore->data.Math); if(headScore==NULL) { //如果头结点为空

headScore=pNodeScore;

pNodeScore->next=NULL; } else

{ //如果头结点不为空

pNodeScore->next=headScore;

headScore=pNodeScore;//将头结点新结点

} } void Input() { int n,i; printf(\"输入几个学生的数据:\"); scanf(\"%d\",&n); for(i=0;i

Add(); printf(\"输入成功!\"); } int Delete() { p_node_score pNodeScore,p1; //p1为pNodeScore的前驱

p1=headScore; if(p1==NULL) {

printf(\"成绩表中没有数据!请先添加数据!\\n\");

return 0; } char DeleteNumber[20];

printf(\"请数入要删除的学生学号:\"); scanf(\"%s\",DeleteNumber); if(strcmp(p1->data.Number,DeleteNumber)==0)

{ //如果要删除的结点在第一个

headScore=p1->next;

pNodeScore=p1;

printf(\"学号为%s的学生信息已经删除!\\n\",DeleteNumber);

return 0; } else

{

pNodeScore=p1->next;

while(pNodeScore!=NULL)

{

if(strcmp(pNodeScore->data.Number,DeleteNumber)==0)

{

p1->next=pNodeScore->next;

printf(\"学号为%s的学生信息已经删除!\\n\",DeleteNumber);

return 0;

}

else

{ //否则,结点向下一个,p1仍为pNodeScore的前驱

p1=pNodeScore;

pNodeScore=pNodeScore->next;

}

} } printf(\"没有此学号的学生!\"); } int Change() {

p_node_score pNodeScore;

pNodeScore=headScore; if(pNodeScore==NULL) {

printf(\"成绩表中没有数据!请先添加数据!\\n\");

return 0; } char EditNumber[20]; printf(\"请输入你要修改的学生学号:\"); scanf(\"%s\",EditNumber); while(pNodeScore!=NULL) {

if(strcmp(pNodeScore->data.Number,EditNumber)==0)

{ //用strcmp比较两字符串是否相等,相等则返回0

printf(\"原来的学生成绩信息如下:\\n\"); //输出原来的成绩信息

printf(\"

学号

|

姓名

| 语文成绩

| 英语成绩| 高数成绩\\n\");

PrintScore(pNodeScore->data);

printf(\"语文新成绩:\");

scanf(\"%s\",pNodeScore->data.Chinese);

printf(\"英语新成绩:\");

scanf(\"%s\",pNodeScore->data.English);

printf(\"高数新成绩:\");

scanf(\"%s\",pNodeScore->data.Math);

printf(\"成绩已经修改!\");

return 0;

}

pNodeScore=pNodeScore->next; //如果不相等,pNodeScore则指向下一个结点

} printf(\"没有此学号的学生!\\n\"); //如果找到最后都没有,则输出没有此学号的学生

} int Find() {

p_node_score pNodeScore;

pNodeScore=headScore; if(pNodeScore==NULL) {

printf(\"成绩表中没有数据!请先添加数据!\\n\");

return 0; } char FindNumber[20]; printf(\"请输入你要查找的学生学号:\"); scanf(\"%s\",FindNumber); while(pNodeScore!=NULL) {

if(strcmp(pNodeScore->data.Number,FindNumber)==0)

{

printf(\"你要查找的学生成绩信息如下:\\n\");

printf(\"

学号

|

姓名

| 语文成绩

| 英语成绩| 高数成绩\\n\");

PrintScore(pNodeScore->data);

return 0;

}

pNodeScore=pNodeScore->next; } printf(\"没有此学号的学生!\\n\"); } int main()

//主函数 { int choice=0; headScore=NULL; int c; do {

system(\"color 2f\");

//运行环境背景颜色.

printf(\"\\n\\n\\t\\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n\\t\\t\");

printf(\"\\n\\t\\t\\t 学生成绩管理系统 \\t\\t\\t\");

printf(\"\\n\\n\\t\\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\\n\\t\\t\");

printf(\"\\n\\t\\t\\t1.输入成绩信息\\n\\t\\t\\t2.输出成绩信息\\n\\t\\t\\t3.添加成绩信息\\n\\t\\t\\t\");

printf(\"4.修改成绩信息\\n\\t\\t\\t5.删除成绩信息\\n\\t\\t\\t6.查询成绩信息\\n\\t\\t\\t7.退出\");

printf(\"\\n\\n\\t\\t\\t请选择:\");

scanf(\"%d\",&c);

switch(c)

{

case 1:system(\"cls\");Input();break;

case 2:system(\"cls\");View();break;

case 3:system(\"cls\");Add();break;

case 4:system(\"cls\");Change();break;

case 5:system(\"cls\");Delete();break;

case 6:system(\"cls\");Find();break;

case 7:system(\"cls\");exit(0);

}

}while(1); return 0; }

运行界面如下:

推荐第6篇:《数据结构》说课稿

《数据结构》“最短路径”问题说课稿

一、教材分析

1、特点与地位:

重点中的重点。本课是教材《数据结构》第六章第五节的内容。图是一种典型的非线性数据结构,应用十分广泛。求两结点之间的最短路径问题是图最常见的应用的之一,在交通运输、通讯网络等方面具有一定的实用意义。

2、重点与难点:

根据高职数据结构教育要求,理论“必需,够用”,侧重于某项技术的理论依据,重点放在技能培养上。结合学生现有抽象思维能力水平,已掌握基本概念等学情,以及求解最短路径问题的自身特点,确立本课的重点和难点如下:

(1)重点:如何将现实问题抽象成求解最短路径问题,以及该问题的解决方案。 (2)难点:求解最短路径算法的程序实现。

3、教学安排:

最短路径问题包含两种情况:一种是求从某个源点到其他各结点的最短路径,另一种是求每一对结点之间的最短路径。根据教学大纲安排,重点讲解第一种情况问题的解决。安排一个课时讲授。教材直接分析算法,考虑实际应用需要,补充旅游景点线路选择的实例,实例中问题解决与算法分析相结合,逐步推动教学过程。

二、教学目标分析

1、知识目标:掌握最短路径概念、能够求解最短路径。

2、能力目标:

(1)通过将旅游景点线路选择问题抽象成求最短路径问题,培养学生的数据抽象能力。

(2)通过旅游景点线路选择问题的解决,培养学生的独立思考、分析问题、解决问题的能力。 (3)通过算法的程序实现,提高学生的编程能力。

3、素质目标:培养学生讲究工作方法、与他人合作,提高工作效率的职业素质。

三、教法分析

课前充分准备,研读教材,查阅相关资料,制作多媒体课件。教学过程中除了使用传统的“讲授法”以外,主要采用“案例教学法”,同时辅以多媒体课件,以启发的方式展开教学。由于本节课的内容属于图这一章的难点,考虑学生的接受能力,注意与学生沟通,根据学生的反应控制好教学进度是本节课成功的关键。

四、学法指导

1、课前

上次课结课时给学生布置任务,使其有针对性的预习。

2、课中

指导学生讨论任务解决方法,引导学生分析本节课知识点。

3、课后

给学生布置同类型任务,加强练习。

五、教学过程分析

(一)课前复习(3~5分钟)

回顾“路径”的概念,为引出“最短路径”做铺垫。 教学方法及注意事项:

(1)采用提问方式,注意及时小结,提问的目的是帮助学生回忆概念。 (2)提示学生“温故而知新”,养成良好的学习习惯。

(二)导入新课(3~5分钟)

以城市公路网为例,基于求两个点间最短距离的实际需要,引出本课教学内容“求最短路径问题”。 教学方法及注意事项:

(1)先讲实例,再指出概念,既可以吸引学生注意力,激发学习兴趣,又可以实现教学内容的自然过渡。

(2)此处使用案例教学法,不在于问题的求解过程,只是为了说明问题的存在,所以这里的例子只需要概述,能够说明问题即可。

(三)讲授新课(25~30分钟)

1、求某一结点到其他各结点的最短路径(重点)

主要采用案例教学法,提出旅游景点选择的例子,解决如何选择代价小、景点多的路线。 (1)将实际问题抽象成图中求任一结点到其他结点最短路径问题。(3~5分钟) 教学方法及注意事项:

主要采用讲授法,将实际问题用图形表示出来。语言描述转换的方法(用圆圈加标号表示某一景点,用箭头表示从某景点到其他景点是否存在旅游线路,并且将旅途费用写在箭头的旁边。)一边用语言描述,一边在黑板上画图。

注意示范画图只进行一部分,让学生独立思考、自主完成余下部分的转化。

及时总结,原型抽象(景点作为图的结点,景点间的线路作为图的边,旅途费用作为边的权值),将案例求解问题抽象成求图中某一结点到其他各结点的最短路径问题。 ④

利用多媒体课件,向学生展示一张带权有向图,并略作解释,为后续教学做准备。 (2)迪杰斯特拉算法(难点)(17~20分钟) 先讲算法思想,主要采用多媒体教学。 教学方法及注意事项:

① 充分利用课件。将教材中的算法思想细化,分步解释给学生。用投影仪演示给学生看,在有限的时间内,学生一边看投影仪上的文字,一边听教师的分析,提高教学效率。注意讲解后给学生留出适当的思考时间。

② 利用FLASH动画,结合第一步案例中抽象出的有向带权图、算法思想,求解答案。帮助学生进一步理解算法思想。 再讲算法实现,主要采用启发式教学。 教学方法及注意事项:

① 启发式教学,如何在计算机中实现上述算法呢?如何实现按路径长度递增产生最短路径?如何记录求解过程中每一步当前的V0到Vi的最短路径呢?引入dist[ ]数组。 ② 结合案例分析求解最短路径过程中dist[ ]数组的变化过程。(重点)注意此处最好借助黑板,按照算法思想的步骤,逐步修改dist[ ]数组。同样,也是只示范一部分,余下部分由学生独立思考完成。 ③ 程序代码的讲解,注重思路,淡化语言。本课程不是语言课 ,对于实现语言不做要求,鼓励学生自己动手将教材提供程序做适当修改,用C++实现,培养他们的编程能力。

2、求每一对结点之间的最短路径(5~6分钟)

两种思路:一种重复执行n次Dijkstra算法,另一种弗洛伊德(Floyed)算法。

教学方法及注意事项:此处只介绍算法思想,算法实现给学生作为拓展内容,自由把握。

(四)课堂小结(3~5分钟)

1、明确本节课重点Dijkstra算法,及算法实现的辅助数组dist[ ]的变化过程。

2、提示学生,在案例中数据抽象时,用结点表示活动,用有向边便是活动之间的优先关系,这种方式形成的图又可以解决哪类实际问题呢?引导学生预习,为下次课的学习埋下伏笔。

(五)布置作业(1~2分钟)

1、书面作业:P174 6.7

2、复习本次课内容,预习下次课内容。

至此,整个教学过程结束,注意留出1~3分钟机动时间,准备一道备用习题,灵活把握时间安排。

六、教学特色

以旅游路线选择为主线,灵活采用案例教学、示范教学、多媒体课件等多种手段辅助教学,使枯燥的理论讲解生动起来。在顺利开展教学的同时,体现所讲内容的实用性,提高学生的学习兴趣。

推荐第7篇:课程设计(数据结构)

课程设计题目

1、运动会分数统计

任务:参加运动会有n个学校,学校编号为1……n。比赛分成m个男子项目,和w个女子项目。项目编号为男子1……m,女子m+1……m+w。不同的项目取前五名或前三名积分;取前五名的积分分别为:

7、

5、

3、

2、1,前三名的积分分别为:

5、

3、2;哪些取前五名或前三名由学生自己设定。(m=10 , w=8 , n=15) 功能要求:

1).可以输入各个项目的前三名或前五名的成绩; 2).能统计各学校总分(用链表);

3).可以按学校编号、学校总分、男女团体总分排序输出(快速、基数);

4).可按学校编号查询学校某个项目的情况;可按项目编号查询取得前三或前五名的学校。

界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。

存储结构:学生自己根据系统功能要求自己设计,但是要求运动会的相关数据要存储在数据文件中。

测试数据:要求使用

1、全部合法数据;

2、局部非法数据。进行程序测试,以保证程序的稳定。测试数据及测试结果请在上交的资料中写明;

2、迷宫求解

任务:可以读入一个任意大小的迷宫数据,分别用广度和深度搜索的方法求出一条走出迷宫的路径,并将路径输出(最佳路径); 要求:以较为直观的方式显示结果

3、Huffman编码

任务 :对一篇英文文章,统计各字符出现的次数,实现Huffman编码; 要求:输出每个字符出现的次数和编码,其中求最小权值要求用堆实现;

4、营业窗口队列模拟

任务:实现具有n(n=3)个窗口的现实队列模拟,统计每人的等待时间。 要求:

1).随机产生顾客的到达时间和服务时间存盘。 2).利用存盘数据实现队列的插入和删除。 2).当有顾客离开时,根据队列长度调整队尾。 3).考虑顾客中途离队的情况。 4).考虑顾客具有优先级的情况。

5、公交线路提示

任务:建立南京主要公交线路图。 要求:输入任意两站点,给出最佳的乘车线路和转车地点。

6、家谱管理系统

任务:实现具有下列功能的家谱管理系统 功能要求:

1).输入文件以存放最初家谱中各成员的信息,成员的信息中均应包含以下内容:姓名、出生日期、婚否、地址、健在否、死亡日期(若其已死亡),也可附加其它信息、但不是必需的。

2).实现数据的存盘和读盘。 3).以图形方式显示家谱。

4).显示第n 代所有人的信息。

5).按照姓名查询,输出成员信息(包括其本人、父亲、孩子的信息)。 6).按照出生日期查询成员名单。 7).输入两人姓名,确定其关系。 8).某成员添加孩子。

9).删除某成员(若其还有后代,则一并删除)。 10).修改某成员信息。

11).按出生日期对家谱中所有人排序。

12).打开一家谱时,提示当天生日的健在成员。

要求:建立至少30个成员的数据,以较为直观的方式显示结果,并提供文稿形式以便检查。

界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。

存储结构:学生自己根据系统功能要求自己设计,但是要求相关数据要存储在数据文件中。测试数据:要求使用

1、全部合法数据;

2、局部非法数据。进行程序测试,以保证程序的稳定。测试数据及测试结果请在上交的资料中写明;

7、排序算法比较

设计要求:利用随机函数产生10个样本,每个样本有50000随机整数,利用直接插入排序、折半插入排序,表插入排序,希尔排序,起泡排序、快速排序、选择排序、堆排序,归并排序,基数排序十种排序方法进行排序(结果为由小到大的顺序),并统计每一种排序所耗费的平均时间(统计为图表坐标形式)。

8、算术表达式求值 [问题描述]

一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正整数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。编程利用“算符优先法”求算术表达式的值。 [基本要求] (1) 从键盘读入一个合法的算术表达式,输出正确的结果。 (2) 显示输入序列和栈的变化过程。

9、电子小字典

基本要求:建立一个微型电子字典,实现生词的加入,单词的查找、删除,修改等操作。

数据结构:键树

10、校园导游程序

[问题描述]用无向网表示你所在学校的校园景点平面图,图中顶点表示主要景点,存放景点的编号、名称、简介等信息,图中的边表示景点间的道路,存放路径长度等信息。要求能够回答有关景点介绍、游览路径等问题。 [基本要求] (1) 查询各景点的相关信息;

(2) 查询图中任意两个景点间的最短路径。 (3) 查询图中任意两个景点间的所有路径。

(4) 增加、删除、更新有关景点和道路的信息。

11、稀疏矩阵相乘

任务:以三元组形式存储稀疏矩阵,实现矩阵相乘。

12、平衡二叉树

任务:平衡二叉树的建立、结点的插入和删除。

13、B-树

任务:3阶B-树的结点的插入和删除。

14、HASH表

任务:以班级学生姓名(拼音)为关键字,建立HASH涵数,实现HASH表存储,用链地址方法解决冲突。

15、„„(自选合适的题目)

成绩评定细则:

1.正确性:程序是否可以运行,结果是否正确(20分) 2.功能的完备性:是否实现要求的所有子功能(20分)

3.课程设计报告中的算法说明的清晰程度,课程设计报告中总结的深刻程度(20分) 4.独立完成情况( 40分) 总计:100分

加分项目:

1.健壮性:异常处理的情况

2.可读性:代码编写是否规范,是否便于阅读。如函数、变量命名,‘{ }’的缩进,关键位置适量注释等

3.功能的完善:除要求实现的功能外,完成了其它的功能,实现了功能的完善 4.界面的设计:可视化界面,或者交互良好的DOS界面 5.……(自荐加分项目)

代码量要求:>=1000行。

代码总量 = 课设题目1 代码量 + 课设题目2 代码量…… 若代码总量低于1000行,则成绩按比例打折。

编程语言:C或C++语言

编程环境:Microsoft Visual C++ 6.0

检查方式: 1.总体上检查程序的代码量,正确性,可读性,健壮性,功能的完备性,代码量,程序的结构是否合理;局部检查三个以上函数块 2.检查程序时同时检查课程设计报告的电子文档

时间安排:

1 上机时间安排

2 课程设计报告上交时间 3 课程设计检查时间

课程设计报告要求:

1.所有的课程设计报告,均要有封面,包括:课题名称、班级、学号、学生姓名、成绩和指导教师;

2.给出自己采用的数据结构;3.给出算法设计思想;

4.给出实现的源程序,并在必要的代码处给出注释;5.给出测试数据和结果;

6.给出算法的时间复杂度、另外可以提出算法的改进方法;

7.给出结束语:说明完成课程设计的情况,心得体会;课程设计报告的电子文档在上机检查程序时一并检查;书面文档在指定的时间内上交。

推荐第8篇:数据结构课程设计

数据结构课程设计

计算机科学与技术2008级1班

课程设计题目:图书借阅管理系统

姓名:

学号:

一.需求分析说明

图书借阅处理过程简述处理过程主要包含:新增图书上架、办理图证、图书查询、借书、还书等。

(1)新增图书上架新书上架时,需要登记新书的:书名、作者、出版社、总册数的信息。

(2)办理图书借阅证读者办理借书证时,需要登记读者(学生)的学号、姓名。 (3)图书查询读者按照图书编号查询图书基本信息,并可以得知现还有几册可以借阅。

(4)借书每个学生读者最多借5本书。读者借书时,应登记书号、借书日期(年月日)。

2.数据分析数据处理过程中涉及到两个实体:图书和会员;各实体应具有的属性如下:图书(书号、书名、作者,总册数)读者(学号、姓名、班级)由于同一种图书可以有多册上架,

每个读者最多可以借阅5本书,图书借阅的属性如下:借阅(书号、借书日期) 3.功能分析系统功能模块包括:图书增加、图书删除、图书查询、借书、还书;另外还包括图书信息修改和读者信息修改。

二.基本功能

1)图书管理(增加图书、查询图书、删除图书、图书借阅、还书); 2)会员管理(增加会员、查询会员、删除会员、借书信息); 3)系统管理(初始化、载入数据、保存数据、退出程序);

三.程序设计

#include #include #include

#define NULL 0

typedef struct BookInfo{ /////图书结构

int b_Code; ////图书编号

char b_Name[20]; /////名称

int b_Total; /////总数

int b_Out; ///借出数

1 BookInfo* nextbook; //////下一类图书

}BookInfo;

typedef struct MemberInfo{ ///会员结构

long m_Code; /////会员编号

char m_Name[20]; ////会员名字

int l_Codes[6]; /////以借书的编号,最多5

MemberInfo* nextmember; ////下一会员

}MemberInfo;

typedef struct System{ ///管理系统结构

BookInfo* BI;

MemberInfo* MI;

int BookTotal; ////图书类库存量

int MemberTota; /////会员数量

}System;

System* InitSystem();/////

void AddBook(System*);////增加图书

2 BookInfo* SearchBook(System*,int);////查询图书信息

void DelBook(System*);/////删除图书

void BrrowBook(System*);///////借书处理

void TurnBackBook(System*);////还书处理

void AddMember(System*);/////添加会员

void DelMember(System*);////删除会员

MemberInfo* SearchMember(System*,int);/////查询会员信息

void StoreData(System*);

void LoadData(System*);

void ExitSystem();

void main() {

3 System* S=InitSystem();

int sel; do{

cout

cout

cout

cout

cout

cout

cout

do{

cin>>sel;

if(sel>=1&&sel

cout

}while(1);

switch(sel){

case 1:AddBook(S);break;

case 2:SearchBook(S,-1);break;

case 3:DelBook(S);break;

case 4:BrrowBook(S);;break;

case 5:TurnBackBook(S);break;

4 case 6:AddMember(S);break;

case 7:DelMember(S);break;

case 8:SearchMember(S,-1);break;

case 9:LoadData(S);break;

case 10:StoreData(S);break;

default:ExitSystem(); }

}while(1); }

System* InitSystem() {

System* S=(System*)malloc(sizeof(System));

S->BI=(BookInfo*)malloc(sizeof(BookInfo));

S->BookTotal=0;

S->BI->nextbook=NULL;

S->MI=(MemberInfo*)malloc(sizeof(MemberInfo));

S->MemberTota=0;

S->MI->nextmember=NULL;

return S; }

void AddBook(System* S) {

5 int Tempcode;

char sel;

BookInfo* p=S->BI;

BookInfo* t;

BookInfo* m;

int num; do{

cout

cin>>Tempcode;

if(m=SearchBook(S,Tempcode)){

cout

cin>>num;

m->b_Total+=num; }

else{

t=(BookInfo*)malloc(sizeof(BookInfo));

t->b_Code=Tempcode;

cout

cin>>t->b_Name;

cout

cin>>t->b_Total;

t->b_Out=0;

6 t->nextbook=p->nextbook;

p->nextbook=t;

S->BookTotal++; }

cout

cout

cin>>sel;

if(sel==\'n\'||sel==\'N\'){

cout

return; }

}while(1); }

BookInfo* SearchBook(System* S,int code){

BookInfo* bi=S->BI->nextbook;

int bookcode;

if(code==-1){

cout

cin>>bookcode; }

else bookcode=code;

while(bi&&bi->b_Code!=bookcode)bi=bi->nextbook;

7 if(code==-1){

if(!bi)cout

else {

coutb_Code

coutb_Name

coutb_Total

coutb_Out

return bi; }

void DelBook(System* S){

BookInfo* bi;

BookInfo* pl=S->BI;

MemberInfo* memi;

char sel;

int tempcode;

int i; do{

pl=S->BI;

8 bi=pl->nextbook;

memi=S->MI->nextmember;

cout

cin>>tempcode;

while(bi){

if(bi->b_Code==tempcode)break;

pl=bi;

bi=bi->nextbook; }

if(bi==0)cout

else{

pl->nextbook=bi->nextbook;

S->BookTotal--;

while(memi){

for(i=1;il_Codes[0];i++){

if(memi->l_Codes[i]==tempcode)break;

}

if(il_Codes[0]){

for(;il_Codes[0];i++)memi->l_Codes[i]=memi->l_Codes[i+1];

9 memi->l_Codes[0]--;

}

memi=memi->nextmember; }

free(bi); }

cout

cin>>sel;

if(sel==\'N\'||sel==\'n\'){

cout

return; }

}while(1); }

void BrrowBook(System* S) {

BookInfo* bi=S->BI->nextbook;

BookInfo* p;

char sel;

int memcode;

MemberInfo* mp;

int tempcode;

10 do{

cout

cin>>tempcode;

p=SearchBook(S,tempcode);

if(!p){

cout

else{

coutb_Total-p->b_Out)

if(!(p->b_Total-p->b_Out))cout

else{

cout

cin>>memcode;

mp=SearchMember(S,memcode);

if(!mp)cout

else{

if(mp->l_Codes[0]==5)cout

else{

p->b_Out++;

mp->l_Codes[++mp->l_Codes[0]]=tempcode;

cout

}

11 } } }

cout

cin>>sel;

if(sel==\'N\'||sel==\'n\'){

cout

return; }

}while(1); }

void TurnBackBook(System* S) {

BookInfo* bi=S->BI->nextbook;

BookInfo* p;

MemberInfo* mp;

int membercode;

int tempcode;

int i;

char sel; do{

cout

12 cin>>tempcode;

p=SearchBook(S,tempcode);

if(!p){

cout

else{

coutb_Total-p->b_Out)

cout

cin>>membercode;

if(!(mp=SearchMember(S,membercode)))cout

else{

p->b_Out--;

for(i=1;il_Codes[0];i++){

if(mp->l_Codes[i]==tempcode)break;

}

while(il_Codes[0]){

mp->l_Codes[i]=mp->l_Codes[i+1];

i++;

}

mp->l_Codes[0]--;

cout

13 }

cout

cin>>sel;

if(sel==\'N\'||sel==\'n\'){

cout

return; }

}while(1); }

void AddMember(System* S) {

int Tempcode;

char sel;

MemberInfo* p=S->MI;

MemberInfo* t; do{

cout

cin>>Tempcode;

t=(MemberInfo*)malloc(sizeof(MemberInfo));

t->m_Code=Tempcode;

14

cout

cin>>t->m_Name;

t->l_Codes[0]=0;

t->nextmember=p->nextmember;

p->nextmember=t;

S->MemberTota++;

cout

cout

cin>>sel;

if(sel==\'n\'||sel==\'N\'){

cout

return; }

}while(1); }

MemberInfo* SearchMember(System* S,int code) {

MemberInfo* bi=S->MI->nextmember;

int membercode;

int i;

15

if(code==-1){

cout

cin>>membercode; }

else membercode=code;

while(bi&&bi->m_Code!=membercode)bi=bi->nextmember;

if(code==-1){

if(!bi)cout

else {

coutm_Code

coutm_Name

coutl_Codes[0]

for(i=1;il_Codes[0];i++)

coutl_Codes[i]

cout

return bi; }

void DelMember(System* S) {

MemberInfo* bi;

16

MemberInfo* pl;

BookInfo* book;

char sel;

int i;

int tempcode; do{

bi=S->MI->nextmember;

pl=S->MI;

cout

cin>>tempcode;

while(bi){

if(bi->m_Code==tempcode)break;

pl=bi;

bi=bi->nextmember; }

if(!bi)cout

else{

pl->nextmember=bi->nextmember;

S->MemberTota--;

for(i=1;il_Codes[0];i++){

if(!(book=SearchBook(S,bi->l_Codes[i]))){

cout

17

}

else{

book->b_Out--;

book->b_Total--;

} }

free(bi); }

cout

cin>>sel;

if(sel==\'N\'||sel==\'n\'){

cout

return; }

}while(1); }

void StoreData(System* S){

FILE* fp;

BookInfo* bi=S->BI->nextbook;

if(!(fp=fopen(\"BookSys\",\"wb\"))){

18

cout

exit(0); }

fwrite(&(S->BookTotal),sizeof(int),1,fp);

while(bi){

fwrite(bi,sizeof(BookInfo),1,fp);

bi=bi->nextbook; }

MemberInfo* mi=S->MI->nextmember;

fwrite(&(S->MemberTota),sizeof(int),1,fp);

while(mi){

fwrite(mi,sizeof(MemberInfo),1,fp);

mi=mi->nextmember; }

fclose(fp); }

void LoadData(System* S){

FILE* fp;

if(!(fp=fopen(\"BookSys\",\"rb\"))){

cout

19

exit(0); }

BookInfo* bi=S->BI;

BookInfo* tempbi;

fread(&(S->BookTotal),sizeof(int),1,fp);

for(int i=1;iBookTotal;i++){

tempbi=(BookInfo*)malloc(sizeof(BookInfo));

fread(tempbi,sizeof(BookInfo),1,fp);

bi->nextbook=tempbi;

bi=tempbi; }

bi->nextbook=NULL;

MemberInfo* mi=S->MI;

MemberInfo* tempmi;

fread(&(S->MemberTota),sizeof(int),1,fp);

for(i=1;iMemberTota;i++){

tempmi=(MemberInfo*)malloc(sizeof(MemberInfo));

fread(tempmi,sizeof(MemberInfo),1,fp);

mi->nextmember=tempmi;

mi=tempmi; }

20 mi->nextmember=NULL;

fclose(fp); }

void ExitSystem(){

char select;

cout

cout

cin>>select;

if(select==\'y\'||select==\'Y\')exit(0);

if(select==\'n\'||select==\'N\')return; }

四.心得体会

历经大半个学期的努力,我的图书管理系统终于如期完成了。此次做系统给我最大的感触有两个。

第一个就是有了一个利用本专业所学到的知识,来练习,实践的机会。

第二个就是增强了自己的自信心。 通过进行图书借阅管理系统的设计,进一步明确了研制一个管理信息系统的方法和思路,将系统开发的各阶段的基本活动贯穿起来,使我更加形象、具体的了解了管理信息系统。系统开发的过程是一个巩固以前所学的计算机知识,掌握新技能的过程。我从这一阶段工作中收益非浅,通过前段时间的课程设计,我能够融会贯通所学的专业基础知识和专业理论知识,培养我们综合运用专业知识分析问题、解决问题的能力及运用工具软件的能力。不仅弄清了以前对系统开发的一些模糊的认识,而且提高了写代码的水平,培养了严谨的工作作风,为今后在工作岗位上用好管好计算机打下了坚实的基础。

在做系统的过程中,我遇到的最大的困难是调程序方面的。在运行程序的过程中经常会出现程序自行中断,需要进行调试的信息。这些信息使得我不得不反复看书,琢磨程序。在一遍一遍的调试之下,程序终于被调通了。那时,我终于可以上上的舒一口气了。

我的系统规模比较小同时由于我的时间和能力等多方面的因素影响,我们的系统也存在一定的缺陷。

21

22

23

推荐第9篇:数据结构课程设计

课 程 设 计 任 务 书

信息 学院 信息管理与信息系统 专业 09级1班 班 孙鹏

一、

二、课程设计题目: 迷宫求解、一元多项式

课程设计主要参考资料: 数据结构(C语言版) 严蔚敏、吴伟民 编著

数据结构题集(C语言版) 严蔚敏、吴伟民、米宁 编著

数据结构课件

三、设计应解决下列各主要问题:

1.实现迷宫的路径求解,并输出最终路径,标记走过却未选择的路径和最终选择的路径

2.对一元多项式实现加法,减法,乘法,求导的计算,并按指数由大到小排序输出

四、课程设计相关附件(如:图纸、软件等):

五、命题发出日期:2011-3-15 设计应完成日期: 2010-6-20

设计指导教师(签章):

系主任(签章):

指导教师对课程设计的评语

指导教师(签章):

年 月 日

山东科技大学学生课程设计

课程设计1 迷宫问题

一、需求分析:

1.2.3.4.以二维数组Maze[][]表示迷宫

用户输入迷宫的数据:构建迷宫,行数m,列数n 迷宫的入口位置和出口位置可由用户随时设定

若设定的迷宫存在通路,则以长方阵形式将迷宫及其通路输出到标准输出文件(即终端)上,其中,字符“#”表示障碍,字符“*”表示路径上的位置,字符“@”表示“死胡同”,即曾经途径然而不能到达出口的位置,余者用空格符印出。若设定的迷宫不存在通路,则报告相应信息。

5.本程序只求出一条成功的通路。然而,只需要对迷宫求解的函数做小量修改,便可求得全部路径。

二、概要设计:

抽象数据类型线性表的定义如下: ⒈ 设计栈的抽象数据类型定义:

ADT Stack { 数据对象:D={ai:|ai∈PositionSet,i=1„n,n≥0} 数据关系:R1={|ai-1,ai∈d,i=2,„n} 基本操作:

的初始化S GetTop(S,&e) 素

Push(&S,e) Pop(&S,e)

返回其值 }ADT Stack;

⒉ 迷宫的抽象数据类型定义: ADT Maze{ 数据对象:D:={aij,Start,end|aij,Start,end∈{} 0≤i≤m+2,0≤j≤n+2,m,n≥0}

数据关系:R={ROW.COL} Row={|ai-1,aij∈D i=1,„,m+2,j=1,„,n+2}

第1页

操作结果

构造一个空栈,完成栈用e返回栈S的栈顶元将新的元素e压入栈顶 删除栈顶元素,并用eInitStack(&S)

山东科技大学学生课程设计

Col={|aijaij-1∈D}

基本操作: masepath (int i,int j,int m,int n,sqstack &s) 初始条件:已知目前迷宫状态, 传过起始位置,和终止位置 操作结果:搜索迷宫,用sqstack s返回搜索所得路径。如不存在,返回2 }ADT MAZE

三、详细设计:

#include #include #include #define OVERFLOW -2 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define STACK_INIT_SIZE 100 //存储空间初始量 #define STACK_INCREMENT 10//存储空间初始增量

typedef int Status;

typedef struct { int r; int c; }PostType;//坐标位置

迷宫的r行c列 typedef struct { int ord;//通道块在路径上的序号

PostType seat;//通道块的当前坐标位置

int di;//通道块指向下一通道块的方向 }SElemType;//栈元素的类型 typedef struct { SElemType *base;//栈底指针

SElemType *top;//栈顶指针

int stacksize;//栈的最大容量 }Stack;//栈的类型

第2页 山东科技大学学生课程设计

Status InitStack(Stack &S)//初始化栈 { S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType)); if(!S.base)

exit(OVERFLOW);//存储分配失败; S.top=S.base; S.stacksize=STACK_INIT_SIZE; return OK; }//InitStack

Status StackEmpty(Stack S) //判断栈是否为空,如果为空返回TRUE,否则返回FALSE { if(S.top==S.base)

return TRUE;

return FALSE; }//StackEmpty

Status Push(Stack &S,SElemType e) //插入元素为e的栈顶元素 { if(S.top-S.base>=S.stacksize) {

S.base=(SElemType*)realloc(S.base,(S.stacksize+STACK_INCREMENT)*sizeof(SElemType));

if(!S.base)

exit(OVERFLOW);

S.top=S.base+S.stacksize;

S.stacksize+=STACK_INCREMENT; } *S.top++=e; return OK; }//Push

Status Pop(Stack &S,SElemType &e) //删除栈顶元素存入e { if(S.top==S.base)

return ERROR; e=*--S.top;

第3页 山东科技大学学生课程设计

return OK; }//Pop

Status DestroyStack(Stack &S) //销毁栈 { free(S.base); S.top=S.base; return OK; }//DestroyStack

//maze.cpp #define MAXLEN 20//迷宫包括外墙最大行列数目 typedef struct{

int r;

int c;

char adr[MAXLEN][MAXLEN];//可取\' \'\'*\' \'@\' \'#\' }MazeType;

//迷宫类型

Status InitMaze(MazeType &maze){ //初始化迷宫若成功返回TRUE,否则返回FALSE

int m,n,i,j,k=1;

printf(\"输入迷口的行数和列数: \");

scanf(\"%d%d\",&maze.r,&maze.c); //迷宫行和列数

for(i=0;i

maze.adr[0][i]=\'#\';

maze.adr[maze.r+1][i]=\'#\';

}//for

for(i=0;i

maze.adr[i][0]=\'#\';

maze.adr[i][maze.c+1]=\'#\';

}

for(i=1;i

for(j=1;j

maze.adr[i][j]=\' \';//初始化迷宫

printf(\"输入障碍物%d的坐标(以坐标(0,0)结束输入): \",k);

scanf(\"%d%d\",&m,&n);

k++;

while(m!=0)

{

if(m>maze.r || n>maze.c)//越界

第4页 山东科技大学学生课程设计

exit(ERROR);

maze.adr[m][n]=\'#\';//迷宫障碍用\'#\'标记

printf(\"输入障碍物%d的坐标(以坐标(0,0)结束输入): \",k);

scanf(\"%d%d\",&m,&n);

k++;

}

return OK; }//InitMaze

Status Pa(MazeType maze,PostType curpos){ //当前位置可通则返回TURE,否则返回FALSE

if(maze.adr[curpos.r][curpos.c]==\' \')//可通

return TRUE;

else

return FALSE; }//Pa

Status FootPrint(MazeType &maze,PostType curpos){ //若走过并且可通返回TRUE,否则返回FALSE //在返回之前销毁栈S

maze.adr[curpos.r][curpos.c]=\'*\';//\"*\"表示可通

return OK; }//FootPrint

PostType NextPos(PostType &curpos,int i){ //指示并返回下一位置的坐标

PostType cpos;

cpos=curpos;

switch(i){

//1.2.3.4分别表示东,南,西,北方向

case 1 : cpos.c+=1; break;

case 2 : cpos.r+=1; break;

case 3 : cpos.c-=1; break;

case 4 : cpos.r-=1; break;

default: exit(ERROR);

}

return cpos; }//Nextpos

Status MarkPrint(MazeType &maze,PostType curpos){ //曾走过但不是通路标记并返回OK

第5页 山东科技大学学生课程设计

maze.adr[curpos.r][curpos.c]=\'@\';//\"@\"表示曾走过但不通

return OK; }//MarkPrint

void PrintMaze(MazeType &maze) //将最后标记好的迷宫输出 { int i,j; printf(\"\\n输出迷宫的路径:\\n\"); for(i=0;i

printf(\"%4d\",i);//输出列数

printf(\"\\n\"); for(i=0;i

printf(\"%d\",i);//输出行数

for(j=0;j

printf(\"%4c\",maze.adr[i][j]);//输出迷宫

printf(\"\\n\"); } }//PrintMaze

Status MazePath(MazeType &maze,PostType start,PostType end) //若迷宫从入口start到end的通道则求得一条存放在栈中 { Stack S;//初始化栈

PostType curpos; int curstep; SElemType e; InitStack(S); curpos=start; curstep=1; do {

if(Pa(maze,curpos))//当前位置可通过而未曾走过留下足迹

{

FootPrint(maze,curpos);

e.ord=curstep;e.seat=curpos;e.di=1;

Push(S,e);//加入栈路径中

if(curpos.r==end.r && curpos.c==end.c)//到达出口返回TRUE

{

第6页 山东科技大学学生课程设计

if(!DestroyStack(S))

exit(OVERFLOW);

else return TRUE;

}

else

{

curpos=NextPos(curpos,1);//下一位置是当前位置

curstep++;//探索下一步

}

}//if

else//当前位置不能通过

{

if(!StackEmpty(S))

{

Pop(S,e);//提取前一位置

while (e.di==4 && !StackEmpty(S))//4个方向都不能通过则留下记号@ 提取前一个位置进行判断是否是能通过

{

MarkPrint(maze,e.seat);

Pop(S,e);

}

if(e.di

设定当前位置为该新方向上的邻位

{

e.di++;

Push(S,e);

curpos=NextPos(e.seat,e.di);

}

}//if

} }while(!StackEmpty(S)); if(!DestroyStack(S))

exit(ERROR); else return FALSE; }//MazePath

int main() { MazeType maze; PostType start,end; char c;

第7页 山东科技大学学生课程设计

do {

printf(\"**********迷宫求解**********\\n\");

if(!InitMaze(maze))

{

printf(\"\\n 初始化迷宫失败!!!\");

exit(ERROR);

}

do

{

printf(\"\\n请输入入口的坐标:\");

scanf(\"%d%d\",&start.r,&start.c);//输入入口坐标

if(start.r>maze.r || start.c>maze.c)

printf(\"\\n输入错误,请重新输入入口的坐标!!\\n\");

continue;

}

while (start.r>maze.r || start.c>maze.c);

do

{

printf(\"\\n请输入出口的坐标:\");//输入出口的坐标

scanf(\"%d%d\",&end.r,&end.c);

if(end.r>maze.r || end.c>maze.c)

printf(\"\\n输入错误,请重新输入出口坐标!!\\n\");

continue;

}

while (end.r>maze.r || end.c>maze.c);

if(!MazePath(maze,start,end))

printf(\"\\n不能找到一条路径!!!\\n\");

else PrintMaze(maze);//输出迷宫

printf(\"是否要继续?(y/n):\");

scanf(\"%s\",&c); } while (c==\'y\' || c==\'Y\'); } 。测试结果:

第8页

四、山东科技大学学生课程设计

课程设计2 一元多项式

一、需求分析:

第9页 山东科技大学学生课程设计

1.2.3.首先定义一个结构体,其中定义一元多项式中的两个参数:系数和指数和链表中结点的指针域;

然后一一罗列每个在主程序中用到的函数,并一一实现; 最后在主程序中主要完成用户的输入和相关函数的调用。

二、概要设计:

void insert(PLOYList *head,PLOYList *input)

//查找位置插入新链节的函数,且让输入的多项式呈降序排列 PLOYList *creat(char ch) //输入多项式

PLOYList *add(PLOYList *head,PLOYList *pre) //多项式相加,head为第一个多项式建立的链表表头,pre为第二个多项式建立的链表表头

PLOYList *sub(PLOYList *head,PLOYList *pre) //多项式相减

PLOYList *mul(PLOYList *head,PLOYList *pre) //多项式相乘

PLOYList *der(PLOYList *head) //多项式求导

void print(PLOYList *fun) //输出多项式,fun指要输出的多项式链表的表头 void start() //用户选择界面

三、详细设计:

#include #include typedef struct node

//定义节点类型 { float coef;

//多项式的系数

int expn;

//多项式的指数

struct node * next; //结点指针域 }PLOYList; void insert(PLOYList *head,PLOYList *input)

//查找位置插入新链节的函数,且让输入的多项式呈降序排列 {

PLOYList *pre,*now;

int signal=0;

pre=head;

第10页 山东科技大学学生课程设计

if(pre->next==NULL) {pre->next=input;} //如果只有一个头结点,则把新结点直接连在后面

else {

now=pre->next;//如果不是只有一个头结点,则设置now指针

while(signal==0)

{

if(input->expn expn)

{

if(now->next==NULL)

{

now->next=input;

signal=1;

}

else

{

pre=now;

now=pre->next;//始终让新输入的数的指数与最后一个结点中的数的指数比较,小于则插在其后面

}

}

else if( input->expn >now->expn )

{

input->next=now;

pre->next=input;

signal=1;

}//若新结点中指数比最后一个结点即now中的指数大,则插入now之前

else//若指数相等则需合并为一个结点,若相加后指数为0则释放该结点

{

now->coef=now->coef+input->coef;

signal=1;

free(input);

if(now->coef==0)

{

pre->next=now->next;

free(now);

}

}//else } //while

第11页 山东科技大学学生课程设计

}//else }//void

PLOYList *creat(char ch)

//输入多项式 {

PLOYList *head,*input;

float x;

int y;

head=(PLOYList *)malloc(sizeof(PLOYList));

//创建链表头

head->next=NULL;

scanf(\"%f %d\",&x,&y);//实现用户输入的第一个项,包括其指数和系数

while(x!=0)

{

input=(PLOYList *)malloc(sizeof(PLOYList)); //创建新链节

input->coef=x;

input->expn=y;

input->next=NULL;

insert(head,input); //每输入一项就将其排序,是的链表中多项式呈降序排列

scanf(\"%f %d\",&x,&y);

} return head; }

PLOYList *add(PLOYList *head,PLOYList *pre)

//多项式相加,head为第一个多项式建立的链表表头,pre为第二个多项式建立的链表表头 {

PLOYList *input;

int flag=0;

while(flag==0)

{

if(pre->next==NULL)

flag=1; //若该链表为空,则无需进行加法运算,跳出循环

else

{

pre=pre->next;

input=(PLOYList *)malloc(sizeof(PLOYList));

第12页 山东科技大学学生课程设计

input->coef=pre->coef;

input->expn=pre->expn;

input->next=NULL;

insert(head,input); // 把g(x)插入到f(x)中,相当于两者相加,结果保存于f(x)

}

} return head; }

PLOYList *sub(PLOYList *head,PLOYList *pre) //多项式相减 {

PLOYList *input;

int flag=0;

while(flag==0)

{

if(pre->next==NULL)

flag=1;

else

{

pre=pre->next;

input=(PLOYList *)malloc(sizeof(PLOYList));

input->coef=0-pre->coef;//将第二个多项式里的数变为其相反数,再用和加法一样的方法实现减法

input->expn=pre->expn;

input->next=NULL;

insert(head,input);

}

} return head; }

PLOYList *mul(PLOYList *head,PLOYList *pre)//多项式项乘 { PLOYList *hf,*pf,*qa,*qb;

qa = head ->next;

qb = pre ->next;//定义指针指向表头后一个元素,即链表中第一个元素

hf = ( PLOYList * )malloc( sizeof(PLOYList));//新创建一个结点,当做表头

hf ->next = NULL; for ( ;qa;qa = qa ->next)

第13页 山东科技大学学生课程设计

{

for( qb = pre ->next;qb;qb= qb ->next)//用两个循环,实现两个多项式之间每个项相乘,结果用insert函数进行排序与合并

{

pf = ( PLOYList *)malloc(sizeof(PLOYList));

pf ->coef = qa ->coef * qb ->coef;//系数相乘

pf ->expn = qa ->expn + qb ->expn;//指数相加

pf ->next = NULL;

insert( hf,pf);

} } return hf; }

PLOYList *der(PLOYList *head)//多项式求导 { PLOYList *p; p = head ->next; while (p) {

p ->coef = p ->coef * p ->expn;

p ->expn = p ->expn--;

p = p ->next; } return head; }//将多项式的每项系数和指数相乘得到新的系数,指数减一得到新的指数即完成求导

void print(PLOYList *fun) //输出多项式,fun指要输出的多项式链表的表头 {

PLOYList *printing;

int flag=0;

printing=fun->next;

if(fun->next==NULL)//若为空表,则无需输出

{

printf(\"0\\n\");

return;

}

while(flag==0)

{

第14页 山东科技大学学生课程设计

if(printing->coef>0&&fun->next!=printing)

printf(\"+\");

if(printing->coef==1);

else if(printing->coef==-1)

printf(\"-\");

else

printf(\"%f\",printing->coef);

if(printing->expn!=0) printf(\"x^%d\",printing->expn);

else if((printing->coef==1)||(printing->coef==-1))

printf(\"1\");

if(printing->next==NULL)

flag=1;

else

printing=printing->next;

} printf(\"\\n\"); }

void start() //用户选择界面 { printf(\"

#\\n\");

printf(\"

用户选择界面

\\n\");

printf(\" ************************************\\n\");

printf(\" *

*\\n\");

printf(\" *

1.两个一元多项式相加

*\\n\");

printf(\" *

2.两个一元多项式相减

*\\n\");

printf(\" *

3.两个一元多项式相乘

*\\n\");

printf(\" *

4.对一个一个一元多项式求导 *\\n\");

printf(\" *

0.退出系统

*\\n\");

printf(\" *

*\\n\");

printf(\" ************************************\\n\");

printf(\"

\\n\");

printf(\" 注释:输入多项式格式(可无序):系数1 指数1 系数2 指数2 „„ ,并以0 0 结束:\\n\");

printf(\"

\\n\");

printf(\" 请选择操作: \"); }

int main() { PLOYList *f,*g,*pf,*hf,*p;

第15页 山东科技大学学生课程设计

int sign=-1;

start();

while(sign!=0)

{

scanf(\"%d\",&sign);

switch(sign)

{

case 0:

break;

case 1://多项式相加

{

printf(\" 你选择的操作是多项式相加:\\n\");

printf(\" 请输入第一个多项式f(x):\");

f=creat(\'f\');

printf(\" 第一个多项式为:f(x)=\");

print(f);

printf(\" 请输入第二个多项式g(x):\");

g=creat(\'g\');

printf(\" 第二个多项式为:g(x)=\");

print(g);

printf(\" 结果为:F(x)=f(x)+g(x)=\");

f=add(f,g);

print(f);

printf(\"\\n\\n\");

printf(\" 继续请选择相应操作,退出请按0.

break;

}

case 2://多项式相减

{

printf(\" 你选择的操作是多项式相减:\\n\");

printf(\" 请输入第一个多项式f(x):\");

f=creat(\'f\');

printf(\" 第一个多项式为:f(x)=\");

print(f);

printf(\" 请输入第二个多项式g(x):\");

g=creat(\'g\');

printf(\" 第二个多项式为:g(x)=\");

print(g);

printf(\" 结果为:F(x)=f(x)-g(x)=\");

f=sub(f,g);

print(f);

\"); 第16页

山东科技大学学生课程设计

printf(\"\\n\\n\");

printf(\" 继续请选择相应操作,退出请按0.

\");

break;

}

case 3://多项式相乘

{

printf(\" 你选择的操作是多项式相乘:\\n\");

printf(\" 请输入第一个多项式f(x):\");

f=creat(\'f\');

printf(\" 第一个多项式为:f(x)=\");

print(f);

printf(\" 请输入第二个多项式g(x):\");

g=creat(\'g\');

printf(\" 第二个多项式为:g(x)=\");

print(g);

printf(\" 结果为:F(x)=f(x) * g(x)=\");

pf=mul(f,g);

print(pf);

printf(\"\\n\\n\");

printf(\" 继续请选择相应操作,退出请按0.

\");

break;

}

case 4://多项式求导

{

printf(\"您选择的是对一个一元多项式求导:\\n\");

printf(\"请输入一个一元多项式:\");

f = creat(\'f\');

printf(\"这个多项式为:f(x)= \");

print(f);

printf(\"求导结果为:F(x)=f\'(x)= \");

f=der(f);

print(f);

printf(\"\\n\\n\");

printf(\" 继续请选择相应操作,退出请按0.

\");

break;

}

}//swith

}//while }//void

四、测试结果:

第17页 山东科技大学学生课程设计

第18页

推荐第10篇:数据结构课程设计

《数据结构》

课程设计报告

学 号 姓 名 班 级 指导教师

XXX XXX XXX XXX 安徽工业大学计算机学院

2014年6月

利用栈实现迷宫问题的求解

一、问题描述

以一个M*N的长方阵表示迷宫,0和1分别表示迷宫中的通路和墙壁。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出米有通路的结论。

二、设计思路

(1)以二维数组maze[m][n]表示迷宫,数组中元素值为0表示通路,1表示障碍。

(2)其中迷宫的入口位置和出口位置默认于maze数组的起始元素位置和最后个元素位置。

(3)以链表作存储结构的栈类型,实现求解迷宫的非递归程序。

三、数据结构定义 typedef struct{

int x; int y; }item; typedef struct{ int x,y,d; }DataType; typedef struct{ DataType data[1000]; int top; }SeqStack,*PSeqStack;

typedef struct{ DataType data[1000]; int top; }SeqStack,*PSeqStack;

四、程序清单 #include #include #include #define m 6 #define n 8 int maze[m+2][n+2]={{1,1,1,1,1,1,1,1,1,1},

typedef struct{

{1,0,1,1,1,0,1,1,1,1}, {1,0,0,0,0,1,1,1,1,1}, {1,0,1,0,0,0,0,0,1,1}, {1,0,1,1,1,0,0,1,1,1}, {1,1,0,0,1,1,0,0,0,1}, {1,0,1,1,0,0,1,1,0,1}, {1,1,1,1,1,1,1,1,1,1}}; int x; int y; }item;

item move[4]={{0,1},{1,0},{0,-1},{-1,0}};

typedef struct{ int x,y,d; }DataType;

typedef struct{ DataType data[1000]; int top; }SeqStack,*PSeqStack;

PSeqStack Init_SeqStack() {

} PSeqStack p; p=(PSeqStack)malloc(sizeof(SeqStack)); if(p) p->top=-1; return p;

int Empty_SeqStack(PSeqStack p) {

}

int Push_SeqStack(PSeqStack p,DataType x) {

}

int Pop_SeqStack(PSeqStack p,DataType *x) { if(p->top==999) return 0; if(p->top==-1) return 1; else return 0; else {

} p->top++; p->data[p->top]=x; return 1;

} if(Empty_SeqStack(p)) return 0; else {

} *x=p->data[p->top]; p->top--; return 1; void Destroy_SeqStack(PSeqStack *p) {

}

int mazepath(int maze[][n+2],item move[],int x0,int y0) {

PSeqStack S; DataType temp; int x,y,d,i,j; if(*p) free(*p); *p=NULL; return;

temp.x=x0; temp.y=y0; temp.d=-1; S=Init_SeqStack(); if(!S) {

} Push_SeqStack(S,temp); while(!Empty_SeqStack(S)) {

Pop_SeqStack(S,&temp); x=temp.x; y=temp.y; d=temp.d+1; while(d

i=x+move[d].x; j=y+move[d].y; if(0==maze[i][j]) { temp.x=x; printf(\"栈初始化失败!!!\"); return 0;

}

}

} temp.y=y; temp.d=d; Push_SeqStack(S,temp); x=i; y=j; maze[x][y]=-1; if(x==m&&y==n) {

} else d=0; while(!Empty_SeqStack(S)) {

} Destroy_SeqStack(&S); return 1; Pop_SeqStack(S,&temp); printf(\"(%d,%d)

} Destroy_SeqStack(&S); return 0; int main() {

}

五、运行及调试分析 mazepath(maze,move,1,1); return 0;

六、课程设计总结等

在做实验前,一定要将课本上的知识吃透,因为这是做实验的基础,否则,在做设计程序实验时,这将使你做的难度加大,浪费宝贵的时间.使你事倍功半.做实验时,一定要亲力亲为,务必要将每个步骤,每个细节弄清楚,弄明白,实验后,还要复习,思考,这样,你的印象才深刻,记得才牢固,否则,过后不久你就会忘得一干二净,这还不如不做.通过这次程序设计的实验,使我们学到了不少实用的知识,更重要的是,做实验的过程,思考问题的方法,这与做其他的实验是通用的,真正使我们们受益匪浅。

大数相乘

一、问题描述

本问题中,要求输入两个相对较大的正整数,能够通过程序计算出其结果

二、设计思路

1.输入阶段采用一维数组a[],b[] 在输入阶段当大数输入时,大数a,b从高位到低位分别依次存入数组a[ ],b[ ]。

2.调用函数计算阶段采用一维数组c[ ] 在计算过程中,由个位到高位依次计算各位的结果,并依次存入数组c[ ]中。

三、数据结构定义

int x[N],y[N],z[N*N];

四、程序清单 #include #include #define N 80 void mul(int *x,int *y,int *z) { int i,j; for(i=0;i=0) n[i++]=s[j--]-\'0\'; } void iniXY(int *x, int *y) { int i; for(i=0;i=0) printf(\"%d\",z[i--]); printf(\"\\n\"); return 0; }

五、运行及调试分析

六、课程设计总结。

回顾起此次课程设计,至今我仍感慨颇多,的确,从从拿到题目到完成整个编程,从理论到实践,可以学到很多很多的的东西,同时不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正提高自己的实际动手能力和独立思考的能力。

第11篇:数据结构教学大纲

《数据结构与算法》教学大纲

课程编号:030816 适用专业:教育技术学 总学时数:64

学 分:4 编制单位:茂名学院理学院教育与信息技术系 编制时间:2008年6月20日

一、课程地位、性质和任务

《数据结构与算法》课程是计算机相关学科专业的基础课程中的一门重要的核心课程。通过本课程的教学,使学生知道求解非数值类问题的基本模型(表、树、图),模型的特点和适用场合,能够根据问题设计和选择好的算法,为学习后续的操作系统、编译原理和软件工程等专业课程,设计应用程序打下基础。

本课程以提高学生的计算机应用能力和综合素质为目标,通过课程教学,为学生构建数据结构与算法方面的知识体系,使学生一方面能够根据问题选择合适的数据结构,设计高效的算法,提高程序设计能力,另一方面,在工程应用中,具有甄别好算法的能力,也就是要从建模、解模和综合等三个方面,提高学生的程序设计能力。

二、与其他课程的关系

先修课:程序设计基础、离散数学、计算机组成原理、计算机文化基础

三、教学内容、课时安排和基本要求

(一)教学部分 第1章 绪论(2学时) 1.1什么是数据结构 1.2 基本概念和术语

1.3 抽象数据类型的表示与实现

1.4 算法和算法分析(算法及其设计的要求, 算法效率的度量,算法的存储空间需求) 1.5 问题求解

基本要求:

了解:抽象数据类型,算法设计方法与算法分析。

掌握:数据与数据结构、算法的基本概念;问题求解的方法与步骤 重点:数据结构和算法的概念,算法的描述形式和评价方法,问题求解的一般步骤

1 难点:评价算法的标准和评价方法,最坏情况和平均情况的区分。

第2章 线性表(8学时) 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现(线性链表,循环链表,双向链表) 2.4 一元多项式的表示及相加

基本要求:

了解:两种存储结构(顺序存储结构和链式存储结构)及一元多项式的表示及相加。

掌握:要求熟练掌握处理线性表的各种算法。为后继章节的学习打基础。 重点:各种算法。 难点:链表的理解。

第3章 栈与队列(4学时)

3.1 栈(定义,栈的表示和实现)

3.2 栈的应用举例(数制转换,括号匹配的检验,行编辑程序,迷宫求解,表达式求值)

3.3 栈与递归的实现

3.4 队列及其实现(定义,链队列,循环队列) 3.5 *离散事件模拟

教学要求:熟练掌握栈和队列的特性和在不同存储结构前提下的算法实现。栈和队列是表最基本和重要的数据结构,是数据结构课程的基础。

基本要求:

了解: 栈和队列的定义及其实现。

掌握: 熟练掌握栈和队列的特性和在不同存储结构前提下的算法实现。 重点: 栈和队列的算法实现。 难点: 栈和队列的算法实现。

第4章 串(2学时) 4.1 串类型的定义

4.2 串的表示和实现(定长顺序存储,堆分配存储,串的块链存储) 4.3 串的模式匹配算法(求子串位置的定位函数,模式匹配的一种改进算法) 4.4 串操作应用举例(文本编辑,建立词索引表)

2 基本要求:

了解:串的基本概念及主要操作和运算。 掌握:掌握串的基本概念和运算。 重点:主要操作和运算。 难点:模式匹配及串的应用。

第5章 数组(2学时) 5.1 数组的定义

5.2 数组的顺序表示和实现

5.3 矩阵的压缩存储(特殊矩阵,稀疏矩阵) 5.4 广义表的定义 5.5 广义表的存储结构 5.6 m元多项式的表示

5.7 广义表的递归算法(求广义表的深度,复制广义表,建立广义表的存储结构)

基本要求:

了解:了解作为抽象数据类型的数组和C语言的数组。认识到数组可以作为顺序存储结构用于顺序表、字符串和稀疏矩阵的实现。也可以采用链式存储结构。

掌握:掌握基本概念和算法。 重点:算法。

难点:广义表的递归算法。

第6章 树与二叉树(15学时) 6.1 树的定义和基本术语

6.2 二叉树(二叉树的定义,二叉树的性质,二叉树的存储结构) 6.3 遍历二叉树和线索二叉树(遍历二叉树,线索二叉树)

6.4 树和森林(树的存储结构,森林与二叉树的转换,树和森林的遍历) 6.5 树与等价问题

6.6 赫夫曼树及其应用(最优二叉树(赫夫曼树),赫夫曼编码) 6.7 回溯法与树的遍历 6.8 树的计数

基本要求:

3 了解:理解树与森林的定义与术语。

掌握:熟练掌握二叉树性质和遍历算法,掌握树与森林的孩子兄弟存储表示和遍历。掌握哈夫曼树构造的方法和算法。 重点: 树的存储结构和遍历算法。 难点:哈夫曼树构造的方法和算法

第7章 图(11学时) 7.1 图的定义和术语

7.2 图的存储结构(数组表示法,邻接表,十字链表,邻接多重表) 7.3 图的遍历(深度优先搜索,广度优先搜索)

7.4 图的连通性问题(无向图的连通分量和生成树,有向图的强连通分量,最小生成树,关节点和重连通分量)

7.5 有向无环图及其应用(拓扑排序,关键路径)

7.6 最短路径(从某个源点到其余各项点的最短路径,每一对顶点之间的最短路径) 基本要求:

了解:图的基本概念和相关术语。

掌握:图的两种主要存储结构及遍历算法。掌握最小生成树、最短路径和活动网算法的思想。

重点:图的两种主要存储结构及遍历算法。 难点:图的遍历算法,最短路径算法。

第8章 查找(8学时)

9.1 静态查找表(顺序表,有序表,静态树表,索引顺序表) 9.2 动态查找表(二叉排序树和平衡二叉树,B_树和B+树,键树) 9.3 哈希表(定义,构造方法,处理冲突的方法,查找及其分析)

基本要求:

了解: 各种查找法的基本概念及实现的基本思想。

掌握:熟练掌握搜索结构的折半查找、二叉搜索树、平衡二叉树主要搜索算法。掌握哈希表查找算法。 重点:各种算法的基本思想及实现。 难点:哈希表查找算法。

4 第9章 内部排序(8学时) 10.1 概述

10.2 插入排序(直接插入,其他插入,希尔) 10.3 交换排序(冒泡排序、快速排序) 10.4 选择排序(简单,树形,堆) 10.5 归并排序

10.6 基数排序(多关键字,链式) 10.7 排序算法分析

基本要求:

了解:基数排序,排序算法分析方法

掌握:排序的基本概念,插入排序,交换排序,选择排序,归并排序重点:内部排序算法

难点:基数排序(多关键字,链式)

第10章 *外部排序(2学时) 11.1 外存信息的存取 11.2 外部排序的方法 11.3 多路平衡归并的实现 11.4 置换-选择排序 11.5 最佳归并树

基本要求:

了解:外部排序的基本概念和相关术语。

掌握:基本掌握外排算法的基本思想,不同排序方法的比较。 重点:外部排序算法 难点:多路平衡归并的实现 第11章 算法设计的一般方法(2学时)

1.重点

(1)有效算法的概念,问题固有难度的概念;

(2)递归法;分治法;平衡原则;贪心法;动态规划的基本原理; (3)搜索-回溯法的基本原理和本质.2.难点

(1)问题固有难度的概念;

(2)递归分治法的效率分析(写出时间耗费的递推式,并求解); (3)动态规划法中的状态转移方程的确定。

(二)实验、实习部分

课程安排五个类别的实验,实验时数为12课时,其中: 实验

一、线性链表及运算 2课时 实验

二、栈和队列 2课时 实验

三、树和二叉树 4课时 实验

四、图及其应用 2课时 实验

五、查找与排序 2课时

四、课程考核方式

闭卷考试70%、平时作业与实验30%

五、建议教材和教学参考书 参考教材:

1、《数据结构》(C语言描述)高等教育出版社 耿国华主编

2、《数据结构》(C语言版) 清华大学出版社 严蔚敏,吴伟民编者

3、《数据结构题集》(C语言版)清华大学出版社 严蔚敏,吴伟民编者

4、《数据结构》算法实现及解析(第二版) 西安电子科技大学出版社 高一凡

六、说明

1、因课时安排少,教学内容多。建议采用多媒体教学。

2、由于本课程内容较多,在实际教学中可根据大纲内容,进行适当调整。

第12篇:数据结构心得体会

心得体会

数据结构是一门纯属于设计的科目,它需用把理论变为上机调试。在学习科目的第一节课起,鲁老师就为我们阐述了它的重要性。它对我们来说具有一定的难度。它是其它编程语言的一门基本学科。 很多同学都说,数据结构不好学,这我深有体会。刚开始学的时候确实有很多地方我很不理解,每次上课时老师都会给我们出不同的设计题目,对于我们一个初学者来说,无疑是一个具大的挑战。

我记得有节课上遍历二叉树的内容,先序遍历、中序遍历、后序遍历。鲁老师说:这节课的内容很重要,不管你以前听懂没有,现在认真听。说实在的,以前上的内容确实没大听懂,不过听了老师的话,我听得很认真。先序遍历很简单,是三个遍历中,最简单的。而中序遍历听得有点模糊,后序遍历也半懂半懂,我心想如果老师再讲一遍,我肯定能听懂。后来老师画了一个二叉树,抽了同学到黑板上去排序,这个二叉树看似复杂,不过用先序遍历来排,并不难。于是我在下面排好了先序,先序遍历很简单,我有点得意,老师到位置上点了我上去排中序,上去之后排得一塌糊涂。后来老师又讲了一遍,我这才听懂了,鲁老师又安慰我们说,这个二叉树有点难,中序和后序都不好排,要学懂的确要花点功夫才行。我听了老师的话,认真做了笔记,回去再看了当天学的内容。第二堂课,老师还是先讲的先前的内容,画了一个简单的二叉树,让我们排序,又叫同学上去分别排出来,老师又点了我的名,叫我起来辨别排中序那两个同学的答案哪个排正确了,我毫不犹豫的答对了。因为这次的内容,先序遍历二叉树、中序遍历二叉树、后序遍历二叉树,我的确真的懂了,第一次上这个课这么有成就感。渐渐的对这门课有了兴趣。我以为永远都听不懂这个课,现在,我明白了,只要认真听,肯下功夫,这个课也没有什么难的。而数据结构学习的难易程度很大程度上决定于个人的兴趣,把一件事情当做任务去做会很痛苦,当做兴趣去做会很快乐。也希望老师能看到我的改变,在此也感谢老师的辛勤教导。老师没有放弃我,几次点我的名上去,老师一定看得到我的进步。

后来,我每节课都认真听课,老师虽然没有点名,但我还是很认真的听。双亲表示法孩子表示法和孩子兄弟表示法,这些内容我都听得很明白,差不多每节课都认真听课。有时我也会在上课空余时间看看以前的内容,所以,第一遍看课本的时候要将概念熟记于心,然后构建知识框架。数据结构包括线性结构、树形结构、图状结构或网状结构。线性结构包括线性表、栈、队列、串、数组、广义表等,栈和队列是操作受限的线性表,串的数据对象约束为字符集,数组和广义表是对线性表的扩展:表中的数据元素本身也是一个数据结构。除了线性表以外,栈是重点,因为栈和递归紧密相连,递归是程序设计中很重要的一种工具。

其中我了解到:栈 (Stack)是只能在某一端插入和删除的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据; 队列一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入的操作端称为队尾,进行删除的操作端称为队头。队列中没有元素时,称为空队列;链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

想着自己报考自考的专业,也会考数据结构这门,这学期就结束了,或多或少都收获了一些知识。尽管学得还不是很透彻,我相信这对自己的自考会有很大的帮助,所以,即使是结束了这科的内容,我也不会放弃去学习它。

第13篇:数据结构教学大纲

中央广播电视大学“开放教育试点”计算机科学与技术专业(本科)

《数据结构》课程教学大纲

第一部分 大纲说明

一、课程的性质和任务

《数据结构》是计算机科学与技术专业本科生的一门必修课程。本课程介绍如何组织各种数据在计算机中的存储、传递和转换。内容包括:数组、链接表、栈和队列、递归、树与森林、图、堆与优先级队列、集合与搜索结构、排序、索引与散列结构等。课程采用面向对象的观点讨论数据结构技术,并以兼有面向过程和面向对象双重特色的C++语言作为算法的描述工具,强化数据结构基本知识和面向对象程序设计基本能力的双基训练。为后续计算机专业课程的学习打下坚实的基础。

二、先修课要求

面向对象程序设计、计算机数学(离散数学)。

三、课程的教学基本要求

1、掌握重要数据结构的概念、使用方法及实现技术;

2、学会做简单的算法分析,包括算法的时间代价和空间代价。

四、教学方法和教学形式建议

电视授课为主,结合面授辅导、面授或电子邮件答疑,进行必要的上机实验。

五、课程教学要求的层次

1、熟练掌握:要求学生能够全面、深入理解和熟练掌握所学内容,并能够用其知识分析、设计和解答相关的应用问题。

2、掌握:要求学生能够较好地理解和掌握,并且能够做简单的分析。

3、了解:要求学生能够一般地了解的所学内容。

六、课程实验

实验内容和要求由省级电大作出具体规定,从2004年春开始按该课程实验教材规定进行。

第二部分 多种媒体教材一体化总体设计初步方案

一、学时分配

课程教学总学时数为 72学时,4学分,其中讲授学时48,实验24

教 学 内 容

讲授学时

实验学时

一、数据结构基本概念及算法分析

3学时

2学时

二、数组

3学时

2学时

三、链表

3学时

3学时

四、栈和队列

3学时

2学时

五、递归

3学时

2学时

六、树与森林

9学时

4学时

七、集合与搜索

5学时

2学时

八、图

7学时

4学时

九、排序

7学时

3学时

十、索引与散列结构

5学时

二、教学环节

1、电视教学

本课程是计算机专业基础课,内容多且带有一定的抽象性,学习起来有一定难度。为保证教学效果,采取电视集中授课方式。聘请有经验的教师担任主讲教师,尽可能利用多种媒体进行教学,使学生能够很快掌握课程的主要知识和解决问题的方法。

2、面授辅导或答疑

本课程教学过程中,面授辅导和答疑是必不可少的教学环节。各地方电大应聘请有经验、认真负责的教师任教,以习题课、专题讨论或答疑的方式,对课程中的重要概念和典型问题的解决方法进行总结和深入讨论,巩固和加深课堂内学到的知识。面授辅导或答疑安排两周一次为宜。必要时可采用电子邮件方式直接与主讲教师联系进行答疑。

3、自学与练习

自学是获取知识的重要手段。教师讲课只是起到抛砖引玉的作用,关键还在于学生的自学。为达到自学的效果,除读懂教科书中所讲内容外,还需大量做题。其目的是要通过做题弄懂、加深对概念的理解,提高程序设计,解决问题的能力。为此,安排一定的实验上机学时。要求学生珍惜实验机时,真正做到学有所获。

学生在上机做实验前,应事先将程序、调试数据、上机操作顺序准备好,并提前使用这些调试数据人工执行过。目的是提高上机的效率和成功率,严禁抄袭或拷贝他人的成果,自觉培养科学、严谨的作风。

除学校提供的时间外,要求课外学生利用自己可能拥有的计算机条件,完成更多的练习,不通过大量的实践,能力和知识水平得不到有效得提高。

4、考试

考试是对学生掌握知识水平的检验。本着多练多考的原则,各地方电大可以再平时多做一些小考。要求考试内容紧扣大纲要求,既要能够检验学生的掌握情况,又要体现水平。因此,不要出难题、怪题,但也不要过于简单,适当有一些编程题。

课程考试具体规定请参看该课程考核说明。

第三部分 教学内容和教学要求

一、数据结构基本概念及简单的算法分析 3学时

1、教学内容:

什么是数据结构

抽象数据类型及面向对象概念:数据类型;数据抽象与抽象数据类型;面向对象的概念;用于描述数据结构的语言

数据结构的抽象层次

算法定义

性能分析与度量:算法的性能标准;算法的后期测试;算法的事前估计;空间复杂度度量;时间复杂度度量;时间复杂度的渐进表示法;渐进的空间复杂度

2、教学要求:

了解:什么是数据、数据对象、数据元素、数据结构、数据的逻辑结构与物理结构、逻辑结构与物理结构间的关系

了解:什么是数据类型、抽象数据类型、数据抽象和信息隐蔽原则。了解什么是面向对象

了解:算法的定义、算法的特性、算法的时间代价、算法的空间代价

掌握:用C++语言描述算法的方法,能够使用C++语言编写程序

二、数组 3学时

1、教学内容:

作为抽象数据类型的数组:数组的定义和初始化;作为抽象数据类型的数组;数组的顺序存储方式

顺序表:顺序表的定义和特点;顺序表的类定义;顺序表的查找、插入和删除;使用顺序表的事例

字符串:字符串的抽象数据类型;字符串操作的实现;字符串的模式匹配

2、教学要求:

了解:线性表的逻辑结构特性,以及线性表的两种存储实现方式

了解:作为抽象数据类型的数组的定义,数组的按行顺序存储与按列顺序存储

熟练掌握:顺序表的定义与实现,包括搜索、插入、删除算法的实现及其平均比较次数的计算,掌握应用顺序表作为集合的简单操作

了解:稀疏矩阵的定义及其数组实现

熟练掌握:字符串的定义及实现

三、链表 3学时

1、教学内容:

单链表:单链表的结构;单链表的类定义;单链表中的插入与删除;带表头结点的单链表;用模板定义的单链表类;静态链表

循环链表:循环链表的类定义;用循环链表解约瑟夫问题;

多项式及其相加:多项式的类定义;多项式的加法

双向链表

2、教学要求:

了解:链表与数组一样,是一种实现级结构。有动态链表和静态链表之分

了解:链表有单链表、循环单链表、双向链表之分

了解:单链表的结构、特点

掌握:单链表的类定义、构造函数、单链表的插入与删除算法

了解:带表头结点的单链表的优点和类定义及相应操作的实现

熟练掌握:用模板定义的单链表类

了解:循环链表的特点,循环链表的类定义,以及用循环链表解决问题的方法

掌握:双向链表的特点,双向链表的类定义及相关操作的实现,用双向链表解决问题的方法。

四、栈和队列 3学时

1、教学内容:

栈:栈的抽象数据类型;栈的顺序存储表示;栈的链接存储表示

表达式求值:中缀表达式求值;中缀表示到后缀表示的转换

队列 :队列的抽象数据类型;队列的顺序存储表示;队列的链接存储表示;队列的应用举例

优先级队列:优先级队列的定义;优先级队列的存储表示

2、教学要求:

熟练掌握:栈的定义、特性和栈的抽象数据类型,栈的顺序表示、链表表示以及相应操作的实现。特别注意栈空和栈满的条件

了解:在表达式计算时栈是如何使用的,重点了解用后缀表示计算表达式及中缀表示改后缀表示的方法和算法思路

熟练掌握:队列的定义、特性和队列的抽象数据类型,队列的顺序表示、链表表示以及相应操作的实现。特别是循环队列中队头与队尾指针的变化情况

掌握:优先级队列的定义、特性和优先级队列的抽象数据类型,优先级队列的插入与删除算法

五、递归 3学时

1、教学内容:

递归的概念:递归问题的求解

递归过程与递归工作栈:单向递归和尾递归的迭代实现;一般递归问题利用栈实现非递归解法

广义表:广义表的概念;广义表的表示及操作;广义表存储结构的实现;广义表的访问算法;广义表的递归算法

2、教学要求:

掌握:递归的概念。包括什么是递归,有那些种类的递归,递归问题的递归求解方法

掌握:递归过程的机制与利用递归工作栈实现递归的方法

了解:迷宫问题的递归求解思路及如何利用栈实现迷宫问题的非递归解法

掌握:利用递归解决问题的分治法和回溯法

掌握:广义表的定义及其实现方法

掌握:广义表的递归算法

六、树与森林 9学时

1、教学内容:

树和森林的概念:树的定义;树的术语;树的抽象数据类型

二叉树:二叉树的定义;二叉树的性质;二叉树的抽象数据类型

二叉树的表示:顺序表示;二叉链表表示

遍历二叉树:中序遍历;前序遍历;后序遍历;应用二叉树遍历的事例;二叉树的计数

线索化二叉树:线索;中序线索化二叉树

堆:堆的定义;堆的建立;堆的插入与删除;堆的调整算法

树与森林:树的存储表示;森林与二叉树的转换;遍历树;遍历森林

霍夫曼树:路径长度;霍夫曼树;霍夫曼编码

2、教学要求:

了解:树和森林的概念。包括树的定义、树的术语、树的抽象数据类型

掌握:二叉树的概念、性质及二叉树的表示

熟练掌握:二叉树的遍历方法

掌握:线索化二叉树的特性及寻找某结点的前驱和后继的方法

熟练掌握:堆的定义,堆的建立、堆的插入与删除、堆的向上和向下调整等算法以及用来实现优先级队列的方法

掌握:树与森林的实现,重点在用二叉树实现

掌握:森林与二叉树的转换;树的遍历算法

掌握:二叉树的计数方法及从二叉树遍历结果得到二叉树的方法

掌握:霍夫曼树的实现方法、构造霍夫曼编码的方法及带权路径长度的计算

七、集合与搜索 5学时

1、教学内容:

集合及其表示:集合基本概念;以集合为基础的抽象数据类型;用位向量实现集合抽象据类型;用有序链表实现集合的抽象数据类型

并查集:并查集的定义;并查集的实现

简单的搜索结构:搜索的概念;静态搜索结构;顺序搜索;基于有序顺序表的顺序搜索和折半搜索

二叉搜索树:二叉搜索树的定义;二叉搜索树上的搜索;二叉搜索树的插入;二叉搜索树的删除

AVL树:AVL树定义;平衡化旋转;AVL树的插入和删除;AVL树高度

2、教学要求:

掌握:集合的基本概念及其表示方法,包括位数组及有序链表的表示及其相关操作的实现算法

掌握:利用并查集实现集合的方法

熟练掌握:静态搜索表的顺序搜索和折半搜索算法及其性能分析方法

熟练掌握:二叉搜索树的表示、搜索、插入、删除算法及其性能分析方法

掌握:AVL树的平衡化旋转、构造、插入、删除时的调整方法及其性能分析

八、图 7学时

1、教学内容:

图的基本概念:图的基本概念;图的抽象数据类型

图的存储表示:邻接矩阵;邻接表;邻接多重表

图的遍历与连通性:深度优先搜索;广度优先搜索;连通分量;关节点与重连通分量

最小生成树:kruskul算法;prim算法

单源最短路径问题:dijkstra算法

活动网络:AOV网络与拓扑排序;AOE网络与关键路径

2、教学要求:

理解:图的基本概念和图的抽象数据类型

掌握:图的3种存储表示:邻接矩阵、邻接表和邻接多重表。对于前两种,要求掌握典型操作,如构造、求根、找第一个邻接顶点、找下一个邻接顶点等操作的实现算法

熟练掌握:图的两种遍历算法与求解连通性问题的方法。包括深度优先搜索和广度优先搜索算法、求连通分量的方法(不要求算法)

理解:求解关节点及构造重连通图的方法(不要求算法)

掌握:构造最小生成树的Prim算法和Kruskal算法,要求理解算法

理解:如何用Dijkstra方法求解单源最短路径问题(不要求算法)

熟练掌握:活动网络的拓扑排序算法

掌握:求解关键路径的方法

九、排序 7学时

1、教学内容:

概述

插入排序:直接插入排序;折半插入排序;链表插入排序;希尔排序

交换排序:起泡排序;快速排序

选择排序:直接选择排序;锦标赛排序;堆排序

归并排序:归并;迭代的归并排序算法;递归的链表归并排序

基数排序:多关键码排序;链式基数排序

外排序:外排序的基本过程;k路平衡归并;初始归并段的生成;最佳归并树

2、教学要求:

掌握:排序的基本概念和性能分析方法

掌握:插入排序、交换排序、选择排序、归并排序等内排序的方法及其性能分析方法

了解:基数排序方法及其性能分析方法

掌握:多路平衡归并等外排序方法及败者树构造方法

掌握:生成初始归并段及败者树构造方法

掌握:最佳归并树的建立方法

十、索引与散列结构 5学时

1、教学内容:

静态索引结构:线性索引;倒排索引;m路静态查找树

动态索引结构:动态的m路查找树;B树的定义;B树的插入;B树的删除;B+树

散列:散列表与散列方法;散列函数;处理溢出的闭散列方法;处理溢出的开散列方法;散列表分析

2、教学要求:

熟练掌握:静态索引结构,包括线性索引、倒排索引、静态索引树的搜索和构造方法

熟练掌握:动态索引结构,包括B树、B+树的搜索和构造方法

熟练掌握:散列法,包括散列函数的构造、解决冲突的方法

第14篇:数据结构学习心得

数据结构学习心得

北京大学信息科学技术学院

04级计算机2班

00448245 柳明海

1. 前言

首先感谢张老师给我这样一个机会, 来和大家分享学习数据结构的经验。 2. 学习方法。

因为要准备这个话题, 所以我认真的思考了我的学习方法, 但是我觉得基本上我就是上课前看看书、上课时认真听课、下课以后复习复习、当然还有做作业时很认真的去做。根本谈不上什么好方法, 不过我还是有一些话要送给大家。 我能行!

个人觉得这句话非常重要,不知道大家是怎样看待数据结构这门课的, 有多少人觉得数据结构很难呢?我知道还是有一些同学这样觉得的, 有时候我跟我的朋友讲要怎样学,讲了一大堆以后, 他就向我抱怨:我以前c++都没有学好, 数据结构更学不好了, 这哪跟哪的话啊,数据结构与c++没有什么关系,我想假如抱有这样的心态, 自己就不相信自己, 那是不可能学好的, 然后那些觉得数据结构很难的同学, 我想他们应该会很看重数据结构的吧, 然后就一天到晚捧着一本数据结构, 这样不会觉得很累吗?而且因为觉得很难, 就容易不相信自己, 学的效率也不会很好, 个人认为数据结构很好学, 很容易学, 或许这有点妄自菲薄吧, 但是因为我觉得很容易, 当然就会觉得自己没问题, 学得很轻松, 效果也还可以。大家都是从高考走过来的, 应该知道心态的重要性吧, 两种不同的心态, 完全就是两种不同的效果。

学了这么久数据结构了, 我们到底在学些什么呢? 不知道大家有没有想过, 那现在我们现在来归纳一下我们学习的内容吧, 其实学到现在我们也就学了几种普通的数据结构, 象二叉树, 树, 图,还有排序的问题, 前面的线性表和字符串也就是一些概念, 当然还有一个很重要的KMP算法, 然后在每种数据结构中我们也就是学到了若干处理的算法,

我想真正数起来也就是几十个算法吧。 学习数据结构也就是要掌握这几十种算法, 多简单。至于如何掌握每个算法呢, 我想就是多看看书, 重要的是能够理解。

我能独自完成作业!

这里我的定义和张老师的不同, 张老师是鼓励大家讨论的, 不过我发现还是有一些同学就是先问好别人算法,然后再自己写, 虽然这个不算抄袭作业, 但自己基本上没有一个思考问题的过程, 虽然要理解算法也会要思考很多, 但是因为没有自己独立的思考过程, 要自己写程序、写算法的时候根本写不出来, 所以我想如果真的想学好数据结构的话, 最好是能够自己思考问题, 不要刚想了一会就觉得做不出来, 然后就去问其他人。其实张老师给我们的作业还是基于我们的水平的, 我绝对相信我们自己能够独自想出算法, 虽有可能会比较长时间吧, 但是这样肯定会比问其他人学到更多的东西。当然我并不是说不要问同学, 有时候就是脑筋转不过来,一问别人就懂了, 当然问了别人不能只是我知道了这个算法, 还应该去想如何思考才能得到这个算法,这样水平会提高很多。 多实验! 这个就没有太多理由了, 我一直觉得编程是一门熟练科学, 多编程,水平肯定会提高, 最重要的是能够养成一种感觉,就是对程序对算法的敏感, 为什么那些牛人看一个算法一下子就看懂了?而自己要看很久才能弄懂, 而且弄懂了过了一阵子又忘记了?其实这个是因为牛人们以前看的程序很多, 编得也很多, 所以他们有了那种感觉,所以我觉得大家应该多看程序, 多写程序, 培养自己的感觉。 3. 复习和考试的技巧

我想大家应该都有这样的感觉,就是觉得自己什么都掌握了, 但是在考试的时候就是会犯晕, 有时候一出考场就知道错在哪个了, 然后考完以后一对答案,发现其实考得很简单, 应该都是自己会做的, 这个就是与自己的复习和考试的技巧有关系了。

首先就是复习, 前面已经说过其实我们学的算法也就是几十个, 那么我们的任务也就是理解这几十个算法, 复习也就是要加深你的理解。如何理解算法, 然后理解到什么程度呢? 是能默出整个算法吗?其实不是这样的, 数据结构的考试有它的特点, 考过期中考试了, 大家应该都发现数据结构其实不要求你把整个算法背出来, 它注重考察你的理解, 那么怎么考察呢?其实也就是两种方式吧, 一种就是用实例, 就是给你一个例子, 要你用某个算法运行出结果, 我想这个期末考试的时候仍然会有很多这样的题目, 比如排序那块就很好出这样的题目, 要复习这种题目我觉得很简单,就是每个算法都自己用例子去实践一下, 以不变应万变,我期中复习的时候就是这样去做的, 而且考试之前我就觉得那个并查集的题目就很有可能会考, 于是就自己出了几个例子,做了一下。另外一种考察方式就是算法填空和算法改错, 可能有一些同学觉得这种题目很难, 其实我们首先可以确定这两种题目肯定是与书上算法有关系的, 只要理解了书上的算法就可以了,有人觉得看完书以后什么都懂了, 而且要默也默得出来, 其实不是这样的,算法改错和填空主要是考察的细微处, 虽然你觉得你默得出来, 那是能够默出算法的主体部分, 很多细微的地方你就会很容易忽略。我想大家考过期中考以后应该都有这种感觉吧?那要怎样解决这种问题呢? 我觉得有两种方法, 一种就是自己去编程实现, 这种方法比较有意义,还能够提高编程水平,

另外一种就是用实例分析算法的每句话, 我认为这种方法是最有效的。

然后还有一种题目, 就是最后的写算法的题目, 我觉得这种题目还是很好解决的, 只要是能够自己做出作业的, 基本上都会很容易做出来,这也是为什么我前面觉得平时做作业应该自己独立思考的原因,同时做这种题目千万要小心, 尤其是题目简单的时候, 那肯定会有一些小地方要考虑清楚,一不小心就会被扣掉很多分, 这样很不值。

我觉得考试的时候没有太多要讲的, 只要复习好了, 考试的时候细心一点就可以了, 然后就是做一个题目开始就要尽量保证正确,如果觉得留在那里等后面做完了再来检查,这样错误还是很有可能检查不出来, 我期中考试的时候就基本上没有检查, 因为我做每个题目都是确保正确, 用的时间也挺多的, 然后也觉得没有检查的必要了。 4. 结语

谢谢大家, 祝大家期末考出理想的成绩!

2005年11月22日于北京大学

第15篇:数据结构作业

1.(1)问题的描述:设计一个程序exp1-1.cpp,输出所有小于等于n(n为一个大于二的正整数)的素数。要求:(1)每行输出10个素数;(2)尽可能采用较优的算法。

(2)解决思想:判断一个整数n是否为素数,只需要用2~n-1之间的每一个整数去除,如果都不能被整除,那么m就是一个素数。其实可以简化,n不被被2~n-1之间的每一个整数去除,只需被2~根号n之间的每个数去除就可以了。因为如果n能被2~n-1之间任意整数整除,如果这个数大于根号m,那这个数必定对应的还有一个比根号m小的因子 (3)源代码:

#include #include using namespace std; int main() { int n,flag; int count=0; cout

cin>>n; if(n

cout

else

for(int i=2;i

{

flag=0;

for(int j=2;j

{

if(i%j==0)

{

flag=1;

break;

}

}

if(flag==0)

{

cout

count++;

if(count%10==0)

cout

}

}

cout

} return 0; (4)运行结果截图

(5)心得体会:按照素数定义来判断素数时,可以进行一个较为明显的优化,即只需从2枚举到根n即可。

2.(1)问题的描述:编写一个程序exp1-2.cpp,计算任一输入的正整数的各位数字之和,并分析算法的时间复杂度。

(2)解决思想:采用递归的算法,对输入的正整数进行不断的取模运算和取商运算,即可得到该正整数的各位数字之和。时间复杂度为O(1) (3)源代码

exp1-2.cpp

#include using namespace std; int fun(int n) { if(n

return 0; } else

return n%10 + fun(n/10); } int main() {

int n;

cout

cin>>n;

cout

(5)心得体会:当遇到一个复杂问题时,可以从最简单的地方着手,刚开始不知道n是几位数,感觉这个问题有点棘手,心想如果是二位数就好办了,因此脑海中浮现了“递归”的思想,把一个复杂问题转变成简单问题。即把一个正整数n边分解边累加,直到分解完毕。

3.(1)问题的描述:编写一个程序exp1-3.cpp,判断一个字符串是否为“回文”(顺读和倒读都一样的字符串称为“回文”),并分析算法的时间复杂度。

(2)解决思想:依次将字符串两端的字符进行比较,若都相同,则为回文字符串。时间复杂度为O(n)。 (3)源代码:

exp1-3.cpp #include #include using namespace std; #define MAX 1000

int fun(char s[]) { int flag=1; int i,j,n=strlen(s);

for (i=0,j=n-1;i

if (s[i]!=s[j])

{

flag=0;

break;

} return(flag); } int main() { char s[MAX]; cout>s; if (fun(s)==1)

cout

cout

(5)心得体会:如果将这题进行扩展,判断一个正整数是否为回文数,也可以采用类似的算法。将正整数的各位存到数组里,用i从左到右扫描s,用j从右到左扫描s,若s[i]与s[j]不相等,则退出循环,否则继续比较,直到i

第16篇:数据结构课程设计

数据结构课程设计题目(2013年)

一、必做题

1、图书管理系统(线性表) [问题描述]

设计一个程序,记录并统计图书使用情况。 [基本要求] (1)图书信息包括图书ID号,图书名,出版社名,出版年月,馆藏册数。 (2)学生信息包括学号,姓名,班级,在借册数,已还册数,违约次数。

(3)借阅信息包括图书ID号,图书名,学号,姓名,借阅日期,应还日期,归还日期。

(4)采用顺序存储线性表表示图书信息。采用链式存储线性表表示学生信息。采用双向循环链表表示借阅信息 。其中一个双向循环链表表示在借的借阅信息,按照图书ID号非递减排序;另一个双向循环链表表示已还的借阅信息,按照图书ID号非递减排序。 (5)图书信息,学生信息、借阅信息采用文件方式输入。

图书信息示例如下,每条信息一行:

16000001 数据结构 清华大学出版社 2012.10 30 学生信息示例如下,每条信息一行: 161340106 张三 1613401 5 10 借阅信息示例如下,每条信息一行:

标志位1(1 表示借阅 2表示归还) 16000001 数据结构 161340106 张三 2013.9.12 (借阅时表示借阅日期,应还日期自动生成,根据借阅日期+60天; 归还时表示归还日期, 归还日期要在借阅日期之后,应还日期之前,如果超过应还日期,则记录一次违约次数)。

例如借阅: 1 16000001 数据结构 161340106 张三 2013.9.12 归还: 2 16000001 数据结构 161340106 张三 2013.10.20 (6)规定每位学生不能同时借阅同一本书两本及以上。图书归还后,将该条借阅信息从借阅链表中转移到归还链表中。

(7)要求模拟数据中图书信息至少30本以上,学生信息至少20条以上,借阅信息至少50条以上。

(8)能够统计每一本图书被借阅次数(已还),在借册数。查询每一位学生的借阅历史明细记录。统计学生平均借阅次数,最大借阅次数,最少借阅次数。 (9)可在此要求基础上进行功能扩展。

2、算术表达式求值(栈) [问题描述]

一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正实数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。编程利用“算符优先法”求算术表达式的值。 [基本要求] (1) 从键盘或文件读入一个合法的算术表达式,输出正确的结果。 (2) 显示输入序列和栈的变化过程。

(3) 考虑算法的健壮性,当表达式错误时,要给出错误原因的提示。

3、二叉树的应用(二叉树) [问题描述] 编程实现二叉树的建立,先序、中序、后序(递归和非递归方法)、层序遍历,二叉树的高度、繁茂度,交换左右子树,统计叶子节点的数目,判断是否为完全二叉树,按树的形态在屏幕上打印输出。 [基本要求] (1) 从文件中读入建树信息,树的节点数目不小于20个,树的高度不小于4。 (2) 建树信息采用两行英文字符表示,每个英文字符代表一个结点,第1行为树的中序遍历结果,第2行为树的后序遍历结果。

4、Huffman编码与解码(Huffman编码、二叉树) [问题描述] 对一篇英文文章(大于2000个英文字符),统计各字符出现的次数,实现Huffman编码,以及对编码结果的解码。 [基本要求] (1) 输出每个字符出现的次数和编码,其中求最小权值要求用堆实现。

(2) 在Huffman编码后,要将编码表和英文文章编码结果保存到文件中,编码结果必须是二进制形式,即0 1的信息用比特位表示,不能用字符’0’和’1’表示。 (3) 提供读编码文件生成原文件的功能。

5、关键路径问题(图) [问题描述] 设计并实现关键路径的一种应用。 [基本要求] (1)实现拓扑排序和关键路径的发现。 (2)给出一个具体的应用环境。

6、排序算法比较(排序) [问题描述] 利用随机函数产生10个样本(其中之一已为正序,之一为倒序),每个样本有20000随机整数,利用直接插入排序、希尔排序,冒泡排序、快速排序、选择排序、堆排序,归并排序(递归和非递归),基数排序八种排序方法进行排序(结果为由小到大的顺序),并统计每一种排序所耗费的平均时间 [基本要求] (1) 原始数据存在文件中,每个整数一行,方便读入。 (2) 屏幕显示每种排序所花的比较次数。

二、选做题

1、迷宫问题(栈与递归) [问题描述] 利用栈操作实现迷宫问题求解。 [基本要求] (1)随机生成模拟迷宫地图,不少于10行10列,存在文件中。 (2)动态显示每一步的结果 。 (3)可在此基础上有改进方法。

2、家谱管理系统(树) [问题描述] 实现具有下列功能的家谱管理系统 [基本要求] (1)输入文件以存放最初家谱中各成员的信息,成员的信息中均应包含以下内容:姓名、出生日期、婚否、地址、健在否、死亡日期(若其已死亡),也可附加其它信息、但不是必需的。

(2)实现数据的存盘和读盘。 (3)以图形方式显示家谱。 (4)显示第n 代所有人的信息。

(5)按照姓名查询,输出成员信息(包括其本人、父亲、孩子的信息)。 (6)按照出生日期查询成员名单。 (7)输入两人姓名,确定其关系。 (8)某成员添加孩子。

(9)删除某成员(若其还有后代,则一并删除)。 (10)修改某成员信息。

(11)按出生日期对家谱中所有人排序。

(12)打开一家谱时,提示当天生日的健在成员。 (13)要求建立至少30个成员的数据,以较为直观的方式显示结果,并提供文稿形式以便检查。

(14)界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。

(15)存储结构:根据系统功能要求自行设计,但是要求相关数据要存储在数据文件中。测试数据:要求使用

1、全部合法数据;

2、局部非法数据。进行程序测试,以保证程序的稳定。

3、公交线路提示(图) [问题描述] 建立南京主要公交线路图。 [基本要求] (1)输入任意两站点,给出最佳的乘车线路和转车地点。 路线信息:可上网查询最新的公交线路信息

4、社交网络图实现(图) [问题描述] 设计并实现一种简单的社交网络模型图。 [基本要求] (1) 每个人的信息是一个结点,人与人的联系构成边。个人信息里要有地理坐标信息,以便后续应用中能方便找靠近的人。

(2) 根据输入的任意两个人信息,给出他们之间的联系路径,最少经过多少人构成联系。

(3) 根据位置信息的动态变化,找寻附近能够联络的人,能够通过1次中间人能联络的人等。

(4)模拟仿真结点的联络密切程度,根据联络密切程度发现社交网络中的小团体。 (5)可根据自己的创意添加更多的功能。

5、营业窗口队列模拟

任务:实现具有n(n=3)个窗口的现实队列模拟,统计每人的等待时间。 要求:

1).随机产生顾客的到达时间和服务时间存盘。 2).利用存盘数据实现队列的插入和删除。 2).当有顾客离开时,根据队列长度调整队尾。 3).考虑顾客中途离队的情况。 4).考虑顾客具有优先级的情况。

6、电子小字典

任务:建立一个微型电子字典,实现生词的加入,单词的查找、删除,修改等操作。 数据结构:键树

7、稀疏矩阵相乘

任务:以三元组形式存储稀疏矩阵,实现矩阵相乘

8、平衡二叉树

任务:平衡二叉树的建立、结点的插入和删除。

9、B-树

任务:3阶B-树的结点的插入和删除。

10、编写‚连连看‛程序。

11、„„(自选合适的题目)

成绩评定细则:

1.正确性:程序是否可以运行,结果是否正确(20分) 2.功能的完备性:是否实现要求的所有子功能(20分)

3.课程设计报告中的算法说明的清晰程度,课程设计报告中总结的深刻程度(20分) 4.独立完成情况( 40分) 总计:100分

加分项目:

1.工作量和选题难度

2.可读性:代码编写是否规范,是否便于阅读。如函数、变量命名,‘{ }’的缩进,关键位置适量注释等

3.功能的完善:除要求实现的功能外,完成了其它的功能,实现了功能的完善 4.健壮性:异常处理的情况

5.界面的设计:可视化界面,或者交互良好的DOS界面 6.……(自荐加分项目)

代码量要求:>=2200行。

代码总量 = 课设题目1 代码量 + 课设题目2 代码量…… 若代码总量低于2200行,则成绩按比例打折。

编程语言:C、C++ 或 JAVA 任选其一

检查方式: 1.一对一上机检查

2.总体上检查程序的代码量,正确性,可读性,健壮性,功能的完备性,程序的结构是否合理;根据实际情况进行详细的程序代码检查。

时间安排: 1 上机时间安排

2 课程设计报告上交时间 3 课程设计检查时间

课程设计报告要求:

1.课程设计报告封面:包括课题名称、班级、学号、学生姓名、成绩和指导教师;2.课程设计报告目录:每部分内容所在页码; 3.需求分析:给出每道题的需求;

4.概要设计:给出每道题采用的数据结构,算法设计思想,算法的时间复杂度;5.详细设计:给出每道题的源程序,并在必要的代码处给出注释; 6.功能测试:给出每道题的测试数据和结果;

7.完成情况:每道题完成部分和未完成部分,自己最满意的部分;8.代码量:每道题代码的行数和总行数;

9.心得体会:包括课程设计设中遇到的问题,如何解决,编程的体验,感想和建议;10.课程设计报告的电子文档在检查后一周内上交班长。

第17篇:数据结构实验报告

数据结构实验报告

指导教师 姓

名班

级学

号实

验 室

黄梅根

钟志伟 0140703 07310325 S331-B

2008-11-29

单链表的插入和删除实验日志

指导教师:黄梅根

实验时间:2008年10月14日 学院 通信学院 专业信息工程

班级0140703 学号07310325姓名 钟志伟 实验室S331-B

实验题目:

单链表的插入和删除 实验目的:

了解和掌握线性表的逻辑结构和链式存储结构,掌握单链表的基本算法及相关的时间性能分析。 实验要求:

建立一个数据域定义为字符串的单链表,在链表中不允许有重复的字符串;根据输入的字符串,先找到相应的结点,后删除之。 实验主要步骤:

1 分析、理解程序。

2 调试程序,并设计输入数据(如:bat,cat,eat,fat,hat,jat,lat,mat,#),测试程序的如下功能:不允许重复字符串的插入;根据输入的字符串,找到相应的结点并删除。 3 修改程序:

增加插入结点的功能。

将建立链表的方法改为头插入法。

实验结果:

心得体会:

通过本次实验,我了基本上掌握了线性表的逻辑结构和链式存储结构,从中也发现自己在这方面的知识掌握的还不是很扎实,下来要多看书,将基本的知识要掌握牢固。

二叉树操作实验日志

指导教师:黄梅根

实验时间:2008年 10 月28 日 学院 通信学院 专业信息工程

班级0140703 学号07310325姓名 钟志伟 实验室S331-B 实验题目: 二叉树操作

实验目的:

掌握二叉树的定义、性质及存储方式,各种遍历算法。

实验要求:

采用二叉树链表作为存储结构,完成二叉树的建立,先序、中序和后序以及按层次遍历的操作,求所有叶子及结点总数的操作。

实验主要步骤; 1. 分析、理解程序。

2.添加中序和后序遍历算法.3.调试程序,设计一棵二叉树,输入完全二叉树的先序序列,用#代表虚结点(空指针),如ABD###CE##F##,建立二叉树,求出先序、中序和后序以及按层次遍历序列,求所有叶子及结点总数。

实验结果:

心得体会:

通过此次实验,我基本掌握了建立二叉树,并且掌握了先序、中序和后序以及按层次遍历的操作,更好的掌握了书本上的知识。

图的遍历操作实验日志

指导教师:黄梅根

实验时间:2008年 11 月 11 日 学院 通信学院 专业 信息工程

班级 0140703 学号 07310325姓名 钟志伟实验室S331-B 实验题目:

图的遍历操作 实验目的:

掌握有向图和无向图的概念;掌握邻接矩阵和邻接链表建立图的存储结构;掌握DFS及BFS对图的遍历操作;了解图结构在人工智能、工程等领域的广泛应用。 实验要求:

采用邻接矩阵和邻接链表作为图的存储结构,完成有向图和无向图的DFS和BFS操作。 实验主要步骤:

1、分析、理解程序。

2、调试程序。设计一个有向图和一个无向图,任选一种存储结构,完成有向图和无向图的DFS(深度优先遍历)和BFS(广度优先遍历)的操作。

实验结果:

心得体会:

通过本次实验,我掌握了有向图和无向图的一些概念,了解了DFS和BFS对图的遍历操作。

循环链表实验日志

指导教师:黄梅根

实验时间:2008年 11 月 25 日 学院 通信学院 专业 信息工程

班级 0140703 学号 07310325 姓名 钟志伟 实验室S331-B 实验目的:

了解和掌握线性表的逻辑结构和链式存储结构,掌握循环链表的基本算法及相关的时间性能分析。

实验要求:

1.实现循环链表的建立

2.输出循环链表节点的指针序列,要求先输出自身的指针,再输出其指向的 节点的指针。如一个有五个节点的循环链表,各节点地址依次为3109,3290,3106,3595,3390,则输出应为:

3109

3290

3290 3106

3106 3595

3595 3390

3390

3109 3.对链表进行由大到小的排序,输出排序完成后的链表和链表的指针序列。

源代码:

#include\"stdio.h\" #include\"string.h\" #include\"stdlib.h\" #include\"ctype.h\" typedef struct node

//定义结点

{ char data[10];

//结点的数据域为字符串

struct node *next;

//结点的指针域

}ListNode; typedef ListNode * LinkList;

// 自定义LinkList单链表类型 LinkList CreatListR1();

//函数,用尾插入法建立带头结点的单链表 ListNode *LocateNode();

//函数,按值查找结点 void DeleteList();

//函数,删除指定值的结点 void printlist();

//函数,打印链表中的所有值

void DeleteAll();

//函数,删除所有结点,释放内存

//==========按值查找结点,找到则返回该结点的位置,否则返回NULL========== ListNode *LocateNode(LinkList head, char *key) {

ListNode *p=head->next; //从开始结点比较

while(p&&strcmp(p->data,key)!=0) //直到p为NULL或p->data为key止

p=p->next;

//扫描下一个结点

return p;

//若p=NULL则查找失败,否则p指向找到的值为key的结点 }

//==========用尾插入法建立带头结点的单链表=========== LinkList CreatListR1(void) {

char ch[10];

LinkList head=(LinkList)malloc(sizeof(ListNode)); //生成头结点

ListNode *s,*r,*pp;

r=head;

r->next=head;

printf(\"Input # to end \"); //输入\"#\"代表输入结束

printf(\"Please input Node_data:\");

scanf(\"%s\",ch);

//输入各结点的字符串

while(strcmp(ch,\"#\")!=0) {

// pp=LocateNode(head,ch);

//按值查找结点,返回结点指针

// if(pp==NULL)

{

//没有重复的字符串,插入到链表中

s=(ListNode *)malloc(sizeof(ListNode));

strcpy(s->data,ch);

r->next=s;

r=s;

r->next=head;

}

printf(\"Input # to end \");

printf(\"Please input Node_data:\");

scanf(\"%s\",ch);

}

return head;

//返回头指针 } //==========删除带头结点的单链表中的指定结点======= void DeleteList(LinkList head,char *key) {

ListNode *p,*r,*q=head;

p=LocateNode(head,key);

//按key值查找结点的

if(p==NULL ) {

//若没有找到结点,退出

printf(\"position error\");

exit(0);

}

while(q->next!=p)

//p为要删除的结点,q为p的前结点

q=q->next;

r=q->next;

q->next=r->next;

free(r);

//释放结点 } //===========打印链表======= void printlist(LinkList head) {

ListNode *p=head->next;

//从开始结点打印

while(p!=head){ printf(\"%s,%s\\n \",p->data,p->next);

p=p->next;

}

printf(\"\\n\"); } //==========删除所有结点,释放空间=========== void DeleteAll(LinkList head) {

ListNode *p=head,*r;

while(p->next){ r=p->next;

free(p); p=r;

}

free(p); }

//==========主函数============== void main() {

char ch[10],num[10];

LinkList head;

head=CreatListR1();

//用尾插入法建立单链表,返回头指针

printlist(head);

//遍历链表输出其值

printf(\" Delete node (y/n):\"); //输入\"y\"或\"n\"去选择是否删除结点

scanf(\"%s\",num);

if(strcmp(num,\"y\")==0 || strcmp(num,\"Y\")==0){

printf(\"Please input Delete_data:\");

scanf(\"%s\",ch);

//输入要删除的字符串

DeleteList(head,ch);

printlist(head);

}

DeleteAll(head);

//删除所有结点,释放内存 }

实验结果:

心得体会:

通过本次实验,我了解了线性表的逻辑结构和链式结构,从中也发现自己在一些知识上掌握的不是很牢固,自己下来要多看书。

第18篇:数据结构课程设计

数据结构课程设计

题目: 串的查找与替换 学院: 信息科学技术学院

目录

一、设计任务书 ..............................1

二、课程设计题目:串的查找和替换 ............1

三、程序功能简介 ............................1

四、主体内容 ................................1

五、程序运行测试 ............................5

六、心得体会 ................................7

七、附录 ....................................8

一、设计任务书

1、设计目的

(1)学习和巩固数据结构的基本知识。

(2)充分体会在程序设计中数据的重要作用,学会在程序设计中运用数据结构的相关知识解决问题。

2、设计基本要求

(1)符合课程设计题要求,实现相应功能; (2)要求界面友好美观,操作方便易行; (3)注意程序的实用性、安全性;

(4)随时记录设计情况(备查,也为编写设计说明书作好准备); (5)设计成果:设计说明书一份(附录:设计说明书格式及要求);源程序(能编译成可执行文件并能正常运行)。

3、设计组织方法

(1)分组选题:每组一个课程设计题,成员两人,设组长一名,负责该组设计工作的协调、分工等。

(2)设计过程:

1)按组讨论、确定设计方案,确定程序模块,并进行明确分工; 2)各人分别完成自己的设计任务,编写源程序,并调试好; 3)程序汇总、编译。

4、设计时间

2011—2012学年第一学期:第18-20周,共计3周

二、课程设计题目:串的查找和替换

问题描述:打开一篇英文文章,在该文章中找出所有给定的单词,然后对所有给定的单词替换为另外一个单词,再存盘。

三、程序功能简介

该课程设计的功能主要实现串的查找与替换,首先打开一个文档,对该文档进行查找和替换,该课程设计的文档中要包含替换后对文件保存的函数。以免造成替换后文件数据的丢失。

四、主体内容

1、设计分析

(1) 主要函数及其功能

initstr( )从文件初始化数组

inputchatihuan( )从键盘输入要替换的单词

charu(char source[ ],int index,char dest[ ])把要替换的单词插入到被替换单词的位置 tihuans( )调用函数是实现替换 (2)数据结构的设计 本设计所采用的数据结构

数组

1

str[500]保存从文件中读取的字符 chazhao[15]保存被替换的单词 tihuan[15]保存要替换的单词

采用数组操作便于数据分析,思路清晰,便于操作。 (3)算法的设计

a.课程设计中首先要实现初始化数组。 b.为了能够统计要查找的字符出现的次数,需要建立能够查找第一个出现要查找字符的下标的函数和要查看文章中共有多少个要查找的字符的函数。

c.建立能够输入要替换的字符串的函数,该函数可以显示要被替换的字符串和替换的字符串,这样可使思路更为清晰。

d.建立能够替换字符串的函数,实现字符串替换的功能。 e.建立函数能够实现替换后的字符串得以保存。

2、程序说明

#include #include #include/*字符串系统函数*/

FILE *fp; /*声明fp是指针,用来指向FILE类型的对象*/ char str[10000]; /*定义一个字符型数组*/ char chazhao[1000]; char tihuan[1000]; void initstr() /*从文件初始化数组*/ { int i=0; /*定义变量*/ fp=fopen(\"string.txt\",\"r\"); /*重新打开文件*/ while(!feof(fp)) /*循环语句,到达文件尾时返回真值*/ { str[i]=fgetc(fp); /*从文件中读取字符*/ i++; } str[--i]=\'\\0\'; /*循环结束*/ fclose(fp); /*关闭文件*/ } void inputchatihuan() /*输入要替换的字符串*/ { printf(\"输入要查找的单词:\\n\"); /*输出查找提示语*/ scanf(\"%s\",chazhao); /*输入*/ printf(\"输入要替换的单词:\\n\"); /*输出替换提示语*/ scanf(\"%s\",tihuan); /*输入*/ getchar(); /*回车返回*/ } /*查找第一个出现要查找字符的下标*/ int chazhaostring() /*定义函数*/ { 2

int i,j,k; /*定义变量 i,j,k*/ for(i=0;(size_t)i

return i;/*字符串的第一个字符开始循环,知道字符结束,for循环结束*/ } return -1; } void chazhaos() /*查看文章中共有多少个要查找的字符*/ { int i,j,k,all=0; /*定义变量i,j,k,all all的值为0*/ printf(\"输入要查找的单词:\\n\"); scanf(\"%s\",chazhao); for(i=0;(size_t)i=index) { source[i]=source[m]; i--;m--; } i=index; m=0; while(m

3

b=a; if(b==-1) /*选择语句*/ { printf(\" 此单词不存在!\\n\");

return; } else { while(str[b+strlen(chazhao)]!=\'\\0\') /*while循环*/ {str[b]=str[b+strlen(chazhao)]; b++; } str[b]=\'\\0\'; charu(str,a,tihuan); } a=chazhaostring(); } while(a!=-1); printf(\"替换成功\\n\"); printf(\"\\n按回车返回.....\"); getchar(); /*回车返回*/ } void save() /*保存修改后的文章信息*/ { int i=0; FILE *fp; fp=fopen(\"string.txt\",\"w\"); /*写入文件*/ while((size_t)i

scanf(\"%d\",&ch); switch(ch) { case 1:;printf(\"%s\\n\",str);getchar();getchar();break;/*选择1 打开string.txt文件并显示*/ case 2:;chazhaos();break; /*选择2 执行chazhaos()*/ case 3:;tihuans();break; /*选择3 执行tihuans()*/ case 0:save(); exit(0); /*选择0 执行saves(),退出*/ default: printf(\"\\n你输入的数字有误!\\n\"); /*如果上面条件都不成立时运行*/

printf(\"按回车返回\");

getchar(); getchar(); /*回车返回*/ } } }

五、程序运行测试

打开运行界面

输出内容界面

5

查找单词界面

替换单词界面

6

退出界面

六、心得体会

三周的课程设计结束了,在这次的课程设计中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在课程设计过程中,我一开始对自己如何完成一个独立的数据结构茫然不知所措,通过向同学们请教,逐步的了解了如何完成这次课程设计,并且提高了我对串的操作的熟练程度。

课程设计是我们专业课程知识综合应用的实践训练,是我们迈向社会,从事职业工作前一个必不少的过程。“千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义。我今天认真的进行课程设计,学会脚踏实地迈开这一步,就是为明天能稳健地

7

在社会大潮中奔跑打下坚实的基础。

在这次数据结构课程设计过程中,体现出自己单独完成问题的能力以及综合运用知识的能力,体会了学以致用、突出自己劳动成果的喜悦心情,从中发现自己平时学习的不足和薄弱环节,从而加以弥补。

七、附录

1、程序中主要函数列表

initstr( )从文件初始化数组

inputchatihuan( )从键盘输入要替换的单词

charu(char source[],int index,char dest[])把要替换的单词插入到被替换单词的位置

tihuans( )调用函数是实现替换

2、附参考书目

《数据结构(C语言版)》 严蔚敏 吴伟民 清华大学出版社 《数据结构实践指导教程》 阮宏一 华中科技大学出版社 《数据结构》 田鲁怀 电子工业出版社

第19篇:数据结构实验报告

浙江师范大学

实 验 报 告

学 院: 数理与信息工程学院 专 业: 计算机科学与技术 姓 名: 杨富生 学 号: 201531910137 课程名称: 数据结构 指导教师: 钟发荣 实验时间: 2016-06-15

2016年6月15日

实验一

1.实验要求

1.1 掌握数据结构中线性表的基本概念。

1.2 熟练掌握线性表的基本操作:创建、插入、删除、查找、输出、求长度及合并并运算在顺序存储结构上的实验。

2.实验内容

2.1 编写一个函数,从一个给定的顺序表A中删除元素值在x到y之间的所有元素,要求以较高效率来实现。

#include typedef int elemtype; #define maxsize 10 int del(int A[],int n,elemtype x,elemtype y) { int i=0,k=0; while(i=x&&A[i]

A[i-k]=A[i]; i++; } return(n-k); } void main() { int i,j; int a[maxsize]; printf(\"输入%d个数:\\n\",maxsize); for(i=0;i

scanf(\"%d,\",&a[i]);

j=del(a,maxsize,1,3);

printf(\"输出删除后剩下的数:\\n\");

for(i=0;i

\"\\n,a[i]); }

2.2 试写一个算法,在无头结点的动态单链表上实现线性表插入操作INSERT(L,i,b)。

void Insert(Linklist &L,int i,elemtype x) { if(!L) {

} L=(Linklist)malloc(sizeof(Lnode)); (*L).data=x;(*L).next=NULL; } else { if(i==1) {

s=(Linklist)malloc(sizeof(Lnode));

s->data=x;s->next=L;L=s; } else {

p=L;j=1;

while(p&&j

{j++;p=p->next;}

if(p||j>i-1)

return error;

s=(Linklist)malloc(sizeof(Lnode));

s->data=x;s->next=p->next;p->next=s; } } 2.3 生成两个多项式PA和PB,求他们的和,输出“和多项式”。 typedef struct node {int exp; float coef; struct node *next; }polynode; polynode *polyadd(polynode *pa,polynode *pb) { polynode *p,*q,*pre,*r; float x; p=pa->next; q=pb->next; pre=pa; while((p!=NULL)&&(q!=NULL))

if(p->exp>q->exp)

{

r=q->next;

q->next=p;

pre->next=q;

pre=q;

q=r;

}

}

else if(p->exp==q->exp) {

x=p->coef+q->coef;

if(x!=0)

{p->coef=x;

s=p;

}

else

{pre->next=p->next;

free(p);

}

p=pre->next;

r=p;

q=q->next;

free(r); } else

if(p->expexp)

{

pre=p;

p=p->next;

}

if(q!=NULL)

pre->next=q;

free(pb); 2.4 设计一个统计选票的算法,输出每个候选人的得票结果。

typedef int elemtype typedef struct linknode { elemtype data; struct linknode *next; }nodetype; nodetype *create() { elemtype d; nodetype h=NULL,*s,*t; int i=1; printf(\"建立单链表:\\n\"); while(1) {

printf(\"输入第%d个结点数据域\",i);

scanf(\"%d\",&d);

if(d==0)break;

if(i==1)

{

h=(nodetype *)malloc(sizeof(nodetype));

h->data=d;h->next=NULL;t=h;

}

else

{

s=(nodetype *)malloc(sizeof(nodetype));

s->data=d;s->next=NULL;t->next=s;

t=s;

}

i++; } return h; }

void sat(nodetype *h,int a[]) { nodetype *p=h; while(p!=NULL) {

a[p->data]++;

p=p->next; } } void main() { int a[N+1],i; for(i=0;i

a[i]=0; nodetype *head; head=create(); sat(head,a); printf(\"候选人:\"); for(i=1;i

printf(\"%3d\",a[i]); printf(\"\\n\"); }

3.实验心得体会

线性表是最简单的、最常用的一种数据结构,是实现其他数据结构的基础。

5

实验二

1.实验要求

1.1 了解栈和队列的特性,以便灵活运用。 1.2 熟练掌握栈和有关队列的各种操作和应用。

2.实验内容

2.1 设一个算术表达式包括圆括号,方括号和花括号三种括号,编写一个算法判断其中的括号是否匹配。 #include #include #include #define NULL 0 typedef struct list { char str; struct list *next; }list; void push(char,list *); int pop(char.list *); void deal(char *str); main(void) {char str[20]; printf(\"\\n请输入一个算式:\\n\"); gets(str); deal(str); printf(\"正确!\"); getchar(); return 0; } void deal(char *str) {list *L; L=(list *)malloc(sizeof(list)); if(!L) { printf(\"错误!\"); exit(-2); } L->next=NULL; while(*str) {

6 if(*str==\'(\'||*str==\'[\'||*str==\'{\')

push(*str,L); else

if(*str==\')\'||*str==\']\'||*str==\'}\')

if(pop(*str,L))

{puts(\"错误,请检查!\");

puts(\"按回车键退出\");

getchar();exit(-2);

}

str++; } if(L->next) {puts(\"错误,请检查!\"); puts(\"按任意键退出\"); getchar();exit(-2); } } void push(char c,list *L) {list *p; p=(list *)malloc(sizeof(list)); if(!p) { printf(\"错误!\"); exit(-2); } p->str=c; p->next=L->next; L->next=p; } #define check(s) if(L->next->str==s){p=l->next;L->next=p->next;free(p);return(0);} int pop(char c,list *L) { list *p; if(L->next==NULL)return 1; switch(c) { case\')\':check(\'(\') break; case\']\':check(\'[\') break; case\'}\':check(\'{\') break; } return 1;

实验三

1.实验要求

1.1 掌握二叉树,二叉树排序数的概念和存储方法。 1.2 掌握二叉树的遍历算法。

1.3 熟练掌握编写实现树的各种运算的算法。 2.实验内容

2.1 编写程序,求二叉树的结点数和叶子数。 #include #include struct node{ char data; struct node *lchild,*rchild; }bnode; typedef struct node *blink; blink creat() { blink bt; char ch; ch=getchar(); if(ch==\' \') return(NULL); else {

bt=(struct node *)malloc(sizeof(bnode));

bt->data=ch;

bt->lchild=creat();

bt->rchild=creat(); } return bt; } int n=0,n1=0; void preorder(blink bt) { if (bt) {

n++;

if(bt->lchild==NULL&&bt->rchild==NULL)

n1++;

preorder(bt->lchild);

preorder(bt->rchild); } } void main()

8 {

} blink root; root=creat(); preorder(root); printf(\"此二叉数的接点数有:%d\\n\",n); printf(\"此二叉数的叶子数有:%d\\n\",n1); 2.2 编写递归算法,求二叉树中以元素值为X的结点为根的子数的深度。 int get_deep(bitree T,int x) { if(T->data==x) { printf(\"%d\\n\",get_deep(T)); exit 1; } else { if(T->lchild)get_deep(T->lchild,x); if(T->rchild)get_deep(T->rchild,x); } int get_depth(bitree T) { if(!T)return 0; else { m=get_depth(T->lchild); n=get_depth(T->rchild); return(m>n?m:n)+1; } } 2.3 编写程序,实现二叉树的先序,中序,后序遍历,并求其深度。 #include #include struct node{ char data; struct node *lchild,*rchild; }bnode; typedef struct node *blink; blink creat() { blink bt; char ch; ch=getchar(); if(ch==\' \') return(NULL); 9 else { bt=(struct node *)malloc(sizeof(bnode)); bt->data=ch; bt->lchild=creat(); bt->rchild=creat(); } return bt; } void preorder(blink bt) { if (bt) { printf(\"%c\",bt->data); preorder(bt->lchild); preorder(bt->rchild); } } void inorder(blink bt) { if(bt) {

inorder(bt->lchild); printf(\"%c\",bt->data); inorder(bt->rchild); } } void postorder(blink bt) { if(bt) { postorder(bt->lchild); postorder(bt->rchild); printf(\"%c\",bt->data); } } int max(int x,int y) { if(x>y) return x; else

return y; } int depth(blink bt)

10 { if (bt) return 1+max(depth(bt->lchild),depth(bt->rchild)); else return 0; } void main() { blink root; root=creat(); printf(\"\\n\"); printf(\"按先序排列:\"); preorder(root);printf(\"\\n\"); printf(\"按中序排列:\"); inorder(root);printf(\"\\n\"); printf(\"按后序排列:\"); postorder(root);printf(\"\\n\"); printf(\"此二叉数的深度是:\"); printf(\"depth=%d\\n\",depth(root)); } 3.实验心得体会

通过本章学习实验,对树有了初步的认识。树就是一种非线性的数据结构,描述了客观世界中事物之间的层次关系。这种结构有着广泛的应用,一切具有层次关系的问题都可以用树来表示。

#include #include #define len sizeof(struct node) #define null 0 typedef struct node{ int data; int ltag,rtag; struct node *lchild,*rchild; }Treenode; Treenode *pre=null; Treenode *creat(){ Treenode *bt; int n; scanf(\"%d\",&n); if(n!=0){

bt=(Treenode *)malloc(len);

bt->data=n;bt->ltag=0;bt->rtag=0;

bt->lchild=creat();

bt->rchild=creat(); }

11 else bt=null; return bt; } void preorder1(Treenode *t){ if(t!=null){

printf(\"%4d\",t->data);

preorder1(t->lchild);

preorder1(t->rchild); } } void preorder2(Treenode *t){ if(t!=null) {

preorder2(t->lchild);

printf(\"%4d\",t->data);

preorder2(t->rchild); } } void preorder3(Treenode *t){ if(t!=null){

preorder3(t->lchild);

preorder3(t->rchild);

printf(\"%4d\",t->data); } } void InThread(Treenode *T){ Treenode *p; p=T; if(p){ InThread(p->lchild); if(!p->lchild){ p->ltag=1; p->lchild=pre; } if(!pre->rchild){ pre->rtag=1; pre->rchild=p; } pre=p; InThread(p->rchild); } } Treenode *inorderthreading(Treenode *T) { Treenode *Thre; Thre=(Treenode *)malloc(sizeof(Treenode) Thre->lchild=T;

12 Thre->rchild=Thre; pre=Thre; InThread(T); pre->rtag=1; pre->rchild=Thre; Thre->rchild=pre; return Thre; } void InThrTravel(Treenode *Thre) { Treenode *p; p=Thre->lchild; while(p!=Thre){ while(p->ltag==0) p=p->lchild; printf(\"%4d\",p->data); while(p->rtag==1 && p->rchild!=Thre){ p=p->rchild; printf(\"%4d\",p->data); } p=p->rchild; }printf(\"\\n\"); } void main() { Treenode *tree; int i; printf(\"建立二叉树:\\n\"); tree=creat(); printf(\"请选择遍历二叉树的方法:\\n\\n1.先根序遍历.\\n2.中根序遍历.\\n3.后根序遍历.\\n\"); scanf(\"%d\",&i); while(i>3 && i

scanf(\"%d\",&i); } switch(i) { case 1:preorder1(tree);break; case 2:preorder2(tree);break; case 3:preorder3(tree);break; } printf(\"\\n中根序线索遍历:\\n\"); tree=inorderthreading(tree); InThrTravel(tree)

实验四

#include #include #define null 0 #define n 4 #define m 2*n-1 typedef struct { int weight; int parent,llink,rlink; }node; typedef struct { int start; char bits[n+1]; }codetype; typedef struct { char c; codetype code; }element; node tree[m+1]; void inithafumantree(node tree[]) { int i; for(i=0;i

tree[i].parent=0;

tree[i].llink=0;

tree[i].rlink=0; } } void inputweight(node tree[]) { int i; printf(\"请输入各结点的权值:\\n\"); for(i=1;i

printf(\"第%d个结点的权值:\",i);

scanf(\"%d\",&tree[i].weight); } } void select(int pre,int *min1,int *min2) { int i;

14 *min1=*min2 = 0; for(i=1;i= tree[i].weight) { *min2 = *min1; *min1 = i; } else if(tree[*min2].weight>tree[i].weight) *min2=i; } } } void sethuftree(node tree[m+1]){ int i,x1,x2; printf(\"构造哈夫曼树.\\n\\n\"); inithafumantree(tree); inputweight(tree); for(i=n+1;i

select(i-1,&x1,&x2);

tree[x1].parent=i;

tree[x2].parent=i;

tree[i].llink=x1;

tree[i].rlink=x2;

tree[i].weight=tree[x1].weight+tree[x2].weight; } void encode(node tree[],element table[]){ int i,s,f; codetype c; for(i=1;i

table[i].c=tree[i].weight;

c.start=n+1;s=i;

while(f=tree[s].parent)

{ c.bits[--c.start]= (s==tree[f].llink)?\'0\':\'1\';s=f;}

table[i].code=c; } void main(){ int i; element table[n+1]; sethuftree(tree); encode(tree,table); printf(\"\\n输出Huffman编码\\n\"); for(i=1;i

实验五

#include #include #define MAX 1000 #define MAXN 100 typedef struct{ char vexs[MAXN]; int edges[MAXN][MAXN]; int n,e; }MGraph; void createmgraph(MGraph *g) { int i,j,k,w ; char Node=\'a\'; printf(\"\\nPlease input n:\"); scanf(\"%d\",&g->n); printf(\"Please input e:\"); scanf(\"%d\",&g->e); for(j=0;jn;j++) g->vexs[j]=Node++; for(i=0;in;i++)

for(j=0;jn;j++)

if(i==j) g->edges[i][j]=0;

else g->edges[i][j]=MAX;

for(k=0;ke;k++) {

printf(\"Input i,j,w:(eg.0,1,5)\\n\");

scanf(\"%d,%d,%d\",&i,&j,&w);

g->edges[i][j]=w;

printf(\"\\nThe graph is: \\n\\n\");

printf(\"\\t \");

for(k=0;kn;k++) {

printf(\"%3c\",g->vexs[k]);

if(k==g->n-1) printf(\"\\n\\n\");

}

for(i=0;in;i++){

printf(\"\\t%c \",g->vexs[i]);

for(j=0;jn;j++)

if(g->edges[i][j]==MAX) printf(\"%3c\",MAX-923);

else printf(\"%3d\",g->edges[i][j]);

printf(\"\\n\");

} void main() { MGraph *g; g=(MGraph *)malloc(sizeof(MGraph)); createmgraph(g); getchar(); }

实验六

1.实验要求

1.1 熟悉图的各种存储方法。

1.2 掌握遍历图的递归和非递归的算法。 1.3 理解图的有关算法。

2.实验内容

2.1 写出将一个无向图的邻接矩阵转换成邻接表的算法。 void mattolist(int a[][],adjlist b[],int n)

{ for(i=0;i

for(i=0;i

for(j=n-1;j>=0;j--)

if(a[i][j]!=0)

{p=(arcnodetp *)malloc(sizeof(arcnodetp));

p->adjvex=j;

p->nextare=b[i].firstare;

b[i].firstarc=p;

} }

2.2 以邻接表作存储结构,给出拓扑排序算法的实现。 typedef struct vexnode { VertexType vertex; int in; ArecNodeTp * fristarc; }AdjList[vnum]; typedef struct graph { AdjList adjlist; int vexnum,arcnum; }GraphTp; Top_Sort(GraphTp g) { LstackTp *p; int m,i,v; initStack(S); for(i=0;i

if(g.adjlist[i].in==0)/*if(w的入度==0)*/

push(S,&v);/*w入S栈*/

} }

m=0; whlie(!EmptyStack(S)){ Pop(S,&v)//S出栈->v

printf(\"%d\",v);/*输出v*/ m++; p=g.adjlist[i].fristarc;/*p=图g中顶点v的第一个邻接点*/ while(p!=NULL){//p存在

(g.adjlist[p->adjvex].in)--;/*p的入度--*/

if(g.adjlist[p->adjvex].in==0)/*if(p的入度==0)*/

Push(S,p->adjvex);/*p入S栈*/

p=p->nextarc;/*p=图g中的顶点v的下一个邻接点*/ } } if(m

实验七

#include #include #define NULL 0 #define maxsize 100 typedef struct node { int data; struct node *left,*right; }dnode; int n=0; void sort(dnode *t,int c)//将c插入到二叉排序树中 { dnode *p; if(c>=t->data)

if(t->right==NULL)

{ p=(dnode *)malloc(sizeof(dnode));

p->data=c;

p->left=NULL;p->right=NULL;

t->right=p;

}

else sort(t->right,c); if(cdata)

if(t->left==NULL)

{ p=(dnode *)malloc(sizeof(dnode));

p->data=c; p->left=NULL;p->right=NULL;t->left=p;

}

else sort(t->left,c) dnode *creat(){ dnode *ht;int x; ht=(dnode *)malloc(sizeof(dnode)); printf(\"创建二叉排序树 (以0结束输入):\"); scanf(\"%d\",&x); ht->data=x; n++;ht->left=NULL;ht->right=NULL; scanf(\"%d\",&x); while(x>0){

sort(ht,x);n++;

scanf(\"%d\",&x); } return ht; } int find(dnode *b,int x,dnode *a[]) { dnode *stack[maxsize],*p; int top; a[1]=NULL;

if(b!=NULL){ top=1;stack[top]=b; while(top>0){ p=stack[top];top--; if(p->left->data==x || p->right->data==x) a[1]=p; if(p->data==x) {a[0]=p;return 1;} if(p->right!=NULL) { top++;stack[top]=p->right;} if(p->left!=NULL) { top++;stack[top]=p->left;} } } a[0]=p; } dnode *delet(dnode *t){ dnode *p,*q,*s,*f,*a[2]; int flag=0,x; p=(dnode *)malloc(sizeof(dnode)); f=(dnode *)malloc(sizeof(dnode)); printf(\"请输入要删除的结点:\"); scanf(\"%d\",&x);find(t,x,a);p=a[0];f=a[1]; if(p==NULL){printf(\"NO FIND!\\n\");exit(0);} if(p->left==NULL) s=p->right; else if(t->right=NULL) s=p->left; else{ q=p;s=p->left; while(s->right!=NULL)

{q=s;s=s->right;}

if(q==p) q->left=s->left;

else q->right=s->left; p->data=s->data;free(s);flag=1; if(flag==0){ if(f==NULL) t=s; else if(f->left==p) f->left=s;

else f->right=s; } return t; } void inorder(dnode *t){ if(t!=NULL) { inorder(t->left);printf(\"%4d\",t->data); inorder(t->right); } } void main(){ dnode *h;h=creat(); printf(\"中序遍历二叉排序树:\"); inorder(h);printf(\"\\n\"); h=delet(h);

inorder(h);printf(\"\\n\");}

实验八

1.实验要求

1.1 掌握顺序查找、二分法查找、分块查找和哈希表查找的算法。 1.2 能运用线性表的查找方法解决实际问题。 2.实验内容

2.1 编写一个算法,利用二分查找算法在一个有序表中插入一个元素X,并保持表的有序性。

#include #include #define MAXNUM 20 int input(int *);/*输入数据*/ int search(int *,int,int);/*查找插入位置*/ void plug(int *,int,int);/*插入数据*/ void main(void) { int data[MAXNUM],m; int insert=1; m=input(data); printf(\"Input the insert num:\"); scanf(\"%d\",data); insert=search(data,1,m);/*返回插入位置*/ plug(data,insert,m); for(insert=1;insert

printf(\"%3d\",*(data+insert)); getch(); } /*********************************************************/ int input(int *data) { int i,m; printf(\"\\nInput the max num:\"); scanf(\"%d\",&m); printf(\"input data\\n\"); for(i=1;i

scanf(\"%d\",data+i); return m; } /**********************************************************/ int search(int *data,int low,int high)/*递归查找插入位置*/ { int mid; if(low>high) return low;/*没有找到插入数据,返回low*/

21 else{

mid=(low+high)/2;

if(*(data+mid)==*data) retun mid;/*找到插入数据,返回mid*/

else if(*(data+mid)

else if(*()data+mid)>*data) } search(data,low,high); } /**********************************************************/ void plug(int *data,int insert,int m) { int i; for(i=m;i>insert;i--)

*(data+i+1)=*(data+i); *(data+insert)=*data } 2.2 根据给定的数据表,先建立索引表,然后进行分块查找。

#include #include #include #definr N 18 /*元素个数*/ #definr Blocknum 3 /*分块数*/ typedef struct indexterm { int key;/*最大关键字*/ int addr;/*块的起始地址*/ }index; /*索引表数据类型*/ index * CreateList(int data[],int n)/*建索引表*/ { index *p; int m,j,k; m=n/BlockNum;/*分为BlockNum块,每块有m个元素*/ p=(index *)malloc(BlockNum *sizeof(index)); for(k=0;k

(p+k)->key=dat a[m*k];

(p+k)->addr=m*k;

for(j=m*k;j

if(data[j]>(p+k)->key)

(p+k)->key=data[j];/*块的最大关键字*/ } return p; } int BlockSearch(index *list,int rectab[],int n,int m,int k)/*分块查找*/

22 { int low=0,high=m-1,mid,i; int b=n/m;/*每块有b个元素*/ while(low

mid=(low+high)/2;

if((list+mid)->key>=k)

high=mid+1;

else low=mid+1; } if(low

for(i=(list+low)->addr;iadder+b-1&&rectab[i]!=k;i++);

if(iaddr+b-1)

return i;

else return -1; } return -1; } void main() { int record[N]={22,12,13,8,9,20,33,42,44,38,24,48,60,58,74,49,86,53}; int key; index *list; printf(\"please input key:\\n\"); scanf(\"%d\",&key); list=CreateList(record,N); printf(\"data postion id %d\\n\",BlockSearch(list,record,N,BlockNum,key)); } 3.实验心得体会

通过本章的学习,对排序有较高层次的理解与认识,从平时的练习中可以看出排序是数据处理中经常用到的重要运算。有序的顺序表可以采用查找效率较高的折半查找法,而无序的顺序表只能用效率较低的顺序查找法。

23

第20篇:数据结构课程设计

数据结构课程设计

利用栈求表达式的值

2013级计算机科学与技术系

数据结构课程设计

目 录

目 录 ..................................................................................................................................2 摘要 ......................................................................................................................................3 1 引言 ..................................................................................................................................4 1.1问题的提出 .............................................................................................................4 1.2 任务与分析 ............................................................................................................4 2 程序的主要功能 ................................................................................................................5 2.1 程序功能设计 .........................................................................................................5 2.2 附加功能 ................................................................................................................5 2.3功能函数 .................................................................................................................5 3 程序运行平台 ....................................................................................................................6 4总体设计 ............................................................................................................................6 4.1 方案总体设计 .........................................................................................................6 4.2程序流程图 .............................................................................................................7 5程序类的说明 ....................................................................................................................8 5.1主要函数 .................................................................................................................8 5.2 函数间的调用关系..................................................................................................9 5.2.1函数调用流程 ................................................................................................9 5.2.2函数调用说明 ................................................................................................9 6系统测试分析 ..................................................................................................................10 7程序源代码 ......................................................................................................................13 8心得体会 ..........................................................................................................................25 9参考文献 ..........................................................................................................................25

数据结构课程设计

摘要

随着计算机科学与技术的迅猛发展,计算机应用层面的不断普及,利用计算机及相关的计算机编程技术实现对现实生活中一些问题的处理,可以简化生活中的某些问题,给人民生活带来方便。数据结构是一门基于数据类型处理的学科,利用数据结构相关知识处理表达式的合法性及表达式的处理结果可以简化计算、判断表达式。

此软件可以实现判断表达式的合法性,如果表达式合法则进行计算,如果不合法则提醒用户表达式错误,请用户重新输入。在合法的基础上会对表达式进行计算,在计算完成的同时会提醒用户是否继续进行计算,不进行计算则进入是否保存界面。用户可以保存多次记录,并可以随时查看,也可以清楚全部记录,根据用户需求而定。

关键词:表达式的值,数据结构,栈;

数据结构课程设计

1 引言

1.1问题的提出

数据结构是一门理论性很强的学科、思维抽象、难度较大的课程,是专业课和基础课之间的桥梁。该课程的先行课是计算机基础,c语言程序设计,离散数学等,后续课程有操作系统,数据库原理,软件工程等。通过本门课程的学习,我们应该能够透彻的理解各种数据对象的特点,学会数据的组织方法和实现方法,并进一步培养良好的程序设计能力,而且该课程的研究方法对我们学生在校及工作学习都是很有帮助,意义重大。数据结构是计算机科学与技术的一门专门的核心专业基础课,在该专业起着承上启下的作用,学好数据结构对于提高理论认知水平和实践能力都有着极为重要的作用。学好数据结构的最终目的是为了获得新的解决问题的办法。对于现实世界的问题,应该能抽象出一个适当的数学模型,该数学模型在计算机内部的数据结构表示,然后设计一个解决此数学模型的算法,在进行程序编写调试,最后得到问题的解答。

1.2 任务与分析

基于上述数据结构的分析,我们开设了数据结构课程设计这门课。针对这门课程的特点,着重培养我们的动手实践能力,我们的任务是基于visual c++ 6.0运行平台设计出一套完整的c语言算法,解决表达是求值问题。表达式的求值分为几个阶段:首先判断表达式是否正确,针对出现的符号是否是合法字符以及是否是字符重复出现进行判断,此过程运用数据结构中栈的基本原理。然后对于检查过的表达式进行计算,运用数学中的先乘后除再加减,有括号先计算括号的运算规则进行四则运算。最后,在计算完整的基础上询问是否保存本次运行记录,根据相应提示即可进行操作。利用栈求表达式的值,虽然是很简单的程序算法,但是在编写过程中可能也会遇到很多问题,我们组的成员也会通过各种途径进行排难,达到成功运行并解决问题的办法。

数据结构课程设计

2 程序的主要功能

2.1 程序功能设计

编写程序实现表达式求值,即验证某算术表达式的正确性,若正确,则计算该算术表达式的值。主要功能描述如下:

1、从键盘上输入表达式,以“=” 号结束表达式。

2、分析该表达式是否合法:

(1)是数字,则判断该数字的合法性。若合法,则压入数据到堆栈中。 (2)是规定的运算符,则根据规则进行处理。在处理过程中,将计算该表达式的值。

(3)若是其它字符,则返回错误信息。

3、若上述处理过程中没有发现错误,则认为该表达式合法,并打印处理结果。

2.2 附加功能

1、规定表达式的合法性

2、小数计算

3、计算记录的保存与查看

4、其他

(1)规定表达式的合法性,括号配对,不能出现“6++3”、“6+-3”等符号重叠的情况。

(2)表达式开头只能是数字或“(”,表达式中只能有一个“=”。

2.3功能函数

程序中主要包含下面几个功能函数: void initstack():初始化堆栈 int make_str():语法检查并计算

int push_num(double num):将操作数压入堆栈 char procede(char top,char code):处理操作码

数据结构课程设计

int change_opnd(int operate):将字符型操作码转换成优先级 int change_opnd(char code):将操作码压入堆栈 char pop_opnd(opnd *op):将操作码弹出堆栈 int caculate(int cur_opnd):简单计算+,-,*,/ double pop_num(num *nu):弹出操作数

3 程序运行平台

硬件系统:Intel(R)Core(TM) i3-3240 CPU @ 3.40GHz 3.39GHz, 4GB内存,500GB硬盘。

软件系统:windows xp操作系统,visual c++ 6.0 编译软件。

4总体设计

4.1 方案总体设计

(1)定义一个expreion全局表达式结构体expr[1000]存放计算过的表达式(expstr[MAXSIZE])和计算结果(result)、一个计量器(i)、一个表达式字符串、一个操作码栈和一个操作数栈;

(2)把表达式字符串从头到尾逐一扫描,将输入的表达式进行语法检查; (3)第一个字符只能是数字或“(”,最重一个字符只能是“=”; (4)表达式括号必须配对,中间不能出现“=”;

(5)在“(”前面只能是“+、-、*、/、( ”,在“+、-、*、/、=、)”前面只能是数字或“)”;

(6)把表达式字符串从头到尾逐一扫描,直到表达式扫描完毕,操作码栈为空;

(7)把字符根据运算优先级别选择操作;

(8)把表达式中的数值部分字符串转成数值压入操作数栈;

(9)是“(”直接压入到操作码栈,级别比操作码栈顶元素高的,把运算符压入操作码栈;

数据结构课程设计

(10)级别比操作码栈低的,弹出操作码栈的栈顶元素和操作数栈的两个栈顶元素,进行运算后再压入操作数栈;

(11)是“)”,若操作码栈顶是“(”,把弹出操作码栈顶元素,否则“)”视为级别最低的元素,重复7;

(12)最后计算出结果并将其存放在expr[i],计量器加1; (13)重复计算后,将结果保存在文件里,并统计计算次数; (14)查看多次计算结果,以表形式输出; (15)查看本次计算记录,以表形式输出; (16)清除计算记录,重新计算。

4.2程序流程图

main Exit() start() load() ClearFile result() check()

Start2() save() 7

数据结构课程设计

5程序类的说明

5.1主要函数

void start(opnd *op,num *nu)//程序主菜单

void start2(opnd *op,num *nu)//第二层计算选择,子菜单 void load()//显示所有计算记录 void save()//保存计算结果 void check()//显示本次计算结果 void result(opnd *op,num *nu)//计算结果

double caculate(opnd *op,num *nu)//简单计算+,-,*,/ 表达式处理函数: int make_str()//语法检查

double change_num(char str[])//数字字符串转成double型数字 char procede(char top,char code)//处理操作码,判断栈的操作 int change_opnd(char code)//字符型操作码转换优先级,非表达式字符返回-2 栈操作函数:

double get_num(num *nu)//查看操作数栈栈顶 double pop_num(num *nu)//操作数栈出栈

int push_num(num *nu,double da)//压入操作数栈 int empty_num(num *nu)//判空 void initstack(num *nu) char get_opnd(opnd *op)//查看栈顶 char pop_opnd(opnd *op)//出栈 int push_opnd(opnd *op,char co)//压栈 int empty_opnd(opnd *op)//判空 void initstack(opnd *op)//初始化栈

数据结构课程设计

5.2 函数间的调用关系 5.2.1函数调用流程

main():主函数 → start(); ↗load() →start(); start()程序模式函数→清空文件→exit(); ↘make_str()→result(op,nu) →start2()→start(); ↗ load → start(); start2()子菜单 → save() → start2(); ↘ check() → start2(); result(op,nu)计算结果→initstack(op) →initstack(nu) →push_opnd(op,\'=\') →

↗push_num(nu,change_num(str2)); →change_opnd(*ps) ↗push_opnd(op,*ps); ↘procede(get_opnd(op),*ps) →pop_opnd(op); ↘push_num(nu,caculate(op,nu)) caculate(op,nu) →b=pop_num(nu) →a=pop_num(nu) →pop_opnd(op)

5.2.2函数调用说明

main()函数:调用了一个函数start(),start()判断执行查看所有计算记录函数load(),或是清空以往的所有计算记录,或是退出程序,或是检查输入表达式语法make_str()并计算表达式result(op,nu)的操作。

result(op,nu)函数:是计算表达式,调用了初始化栈函数和字符级别判断change_opnd(*ps),若是数字,则调用转化数字change_num(str2)然后压入操作数栈,若是运算符,刚调用判断操作procede(get_opnd(op),*ps),若是“”,则弹出操作码栈的栈顶元素和操作数栈的两个栈顶元素,进行运算caculate(op,nu)后再压入操作数栈,计算完毕后按start()顺序

数据结构课程设计

运行。

start2()函数:在计算结果后调用跟随的选择菜单,进行查看结果check()、保存结果save()、查看计算记录load()、回到主菜单的操作。

6系统测试分析

(1)程序主界面,根据提示选择相应的输入字母选择相应菜单。在系统第一次运行的时候,查看记录是不会有结果的,应当首先进行计算式子,然后进行保存过,才会有结果。

数据结构课程设计

(2)计算式子,根据需要输入了以上三个式子,计算结果都正确无误。计算完毕,输入e结束计算,程序进入子菜单。

(3)在计算完式子以后进入子菜单选择界面,我们对式子进行保存处理。进入(4)。

(4)对刚刚输入计算的式子进行保存,选择s,提示式子已经被保存下来了。接下来我们回到主界面,查看记录。

数据结构课程设计

(5)我们输入了l,程序返回我们刚刚保存的计算记录,并且进行个数统计。

(6)我们对刚才的保存的记录进行清空处理,按c,确定后,返回结果为所有记录为空,我们也可以对此事的系统进行再次查询处理,结果也会发现是没有记录的。最后我们按e,则整个系统退出。

数据结构课程设计

7程序源代码

#include #include #include #include //宏定义

#define MAXSIZE 100 #define N 1000 int i=0;

//表达式数

typedef struct expreion//表达式结构

{ long double result;

char expstr[MAXSIZE]; }expreion; expreion expr[N];//表达式的一个整体容器s

typedef struct//操作码栈定义

{ char code[MAXSIZE]; int top; }opnd;

typedef struct//操作数栈定义

{ double date[MAXSIZE]; int top; }num; //《——opnd栈操作——》:

void initstack(opnd *op)//初始化栈

{ op->top=-1; } int empty_opnd(opnd *op)//判断是否为空栈

{ if(op->top==-1)

return 0; else return 1; }

int push_opnd(opnd *op,char co)//入栈

{

数据结构课程设计

if(op->top==MAXSIZE-1)

{

printf(\"The \"opnd\" stack is full.\");

return 0;

} op->top++; op->code[op->top]=co; return 1; } char pop_opnd(opnd *op)//出栈

{ char a=\'\\0\'; if(op->top==-1)

{

printf(\"error:The \"opnd\" stack is empty.\");

return a;

} a=op->code[op->top]; op->top--; return a; } char get_opnd(opnd *op)//查看栈顶

{ char a=\'\\0\'; if(op->top==-1)

{

printf(\"error:The \"opnd\" stack is empty.\");

return a;

} else

return op->code[op->top]; } //《——num栈操作——》: void initstack(num *nu) { nu->top=-1; } int empty_num(num *nu)//判空

{ if(nu->top==-1)

return 0; else return 1; }

数据结构课程设计

int push_num(num *nu,double da)//入栈

{ if(nu->top==MAXSIZE-1)

{

printf(\"error:The \"date\" stack is full.\");

return 0;

} nu->top++; nu->date[nu->top]=da; return 1; } double pop_num(num *nu)//出栈

{ double a=\'\\0\'; if(nu->top==-1)

{

printf(\"error:The \"date\" stack is empty.\");

return a;

} a=nu->date[nu->top]; nu->top--; return a; } double get_num(num *nu)//查看栈顶

{ if(nu->top!=-1)

return nu->date[nu->top]; } //《——结束栈定义操作——》 //《——函数操作——》:

int change_opnd(char code)//将字符型操作码转换成优先级,非表达式字符反回-2 { switch(code)

{

case \'=\':return 1;break;

case \')\':return 2;break;

case \'+\':return 3;break;

case \'-\':return 3;break;

case \'*\':return 4;break;

case \'/\':return 4;break;

case \'(\':return 0;break;//操作码级别>=0;

case \'1\':case \'2\':case \'3\':case \'4\':case \'5\':case \'6\':case \'7\':

case \'8\':case \'9\':case \'0\':case \'.\': return -1;//操作数级别=-1;

default: return -2;//其它符号级别=-2

数据结构课程设计

} } char procede(char top,char code)//处理操作码,判断栈的操作

{ if(change_opnd(code)==0)//“(”入栈

return (\'

if(change_opnd(code)==2&&change_opnd(top)==0)//“(”和“)”同时出现,“(”出栈,“)”不入栈

return (\'=\');

else

if(change_opnd(code)

return (\'>\');

else

return (\'

} double change_num(char str[])//数字字符串转成double型数字

{ char *s=str; int p=1,q=0;//p=小数点前位数,q=小数点后位数

char d[]=\".\",z[]=\"0\"; double da=0,p1; if(strstr(str,d)==0)//判断是否有小数点

p=strlen(str); else

if(strstr(str,d)==str)//没有输入小数点前的数,如“.032”

{

p=1;

q=strlen(str)-1;

strcpy(str,strcat(z,str));

}

else

{

p=strstr(str,d)-str;

q=strlen(str)-p-1;

}

for(int i=0;i

//小数点前的各位数乘以各自的阶数,然后叠加:123=1*100+2*10+3*1

da=da+((int)str[i]-48)*pow(10,p-i-1);

for(int j=0;j

//小数点后的各位数乘以各自的阶数,然后叠加:0.123=1*0.1+2*0.01+3*0.001

da=da+((int)str[strlen(str)-1-j]-48)*pow(0.1,q-j);

return da; }

数据结构课程设计

int make_str()//语法检查

{ char *p,*p1; int n=0; printf(\"\\n请输入表达式,以“=”结尾:\"); gets(expr[i].expstr); p=expr[i].expstr; p1=p;

while(1)

{

if(*p==\'\\0\')

if(*(p-1)==\'=\')//语法检查结束

break;

else

{//没有以\"=\"结尾

printf(\"\\n表达式以\"=\"结尾。请重新输入:\");

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

if(change_opnd(*p)==2)//一个\")\",n-1

n--;

if(change_opnd(*p)==0)//一个\"(\",n+1

n++;

if(*p1==*p)//第一个字符的判断,只能以“数字”或“(”开头,不能有非法字符

if(change_opnd(*p)>0)

{

printf(\"\\n表达式只能以“数字”或“(”开头。请重新输入:\");

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

else

if(change_opnd(*p)==-2)

{

printf(\"\\n表达式\"%c\"为非法字符。请重新输入:\",*p);

gets(expr[i].expstr);

数据结构课程设计

p=expr[i].expstr;

n=0;

continue;

}

else

{//合法刚跳到下一个字符

p=p+1;

continue;

}

if(change_opnd(*p)==-2)//非法字符判断

{

printf(\"\\n表达式\"%c\"为非法字符。请重新输入:\",*p);

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

if(change_opnd(*p)==0)//\"(\"前一个字符只能是\"+、-、*、/、(\"

{

if(change_opnd(*(p-1))4)

if(change_opnd(*(p-1))!=0)

{

printf(\"\\n表达式\"%c\"或\"%c\"不符合语法。请重新输入:\",*(p-1),*p);

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

}

if(change_opnd(*p)>0)//\"+、-、*、/、=、)\"前一个字符只能是数字和\")\"

if(change_opnd(*(p-1))!=-1)

if(change_opnd(*(p-1))!=2)

{

printf(\"\\n表达式\"%c\"或\"%c\"不符合语法。请重新输入:\",*(p-1),*p);

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

if(change_opnd(*p)==1)//判断表达式中是否有\"=\"重复出现,最后括号是否配对

数据结构课程设计

{

if(*(p+1)!=\'\\0\')

{

printf(\"\\n表达式中\"=\",只能出现在表达式结束处。请重新输入:\");

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

if(n!=0)

{

printf(\"\\n表达式括号不配。请重新输入:\");

gets(expr[i].expstr);

p=expr[i].expstr;

n=0;

continue;

}

}

p=p+1;

}

return 1; }

double caculate(opnd *op,num *nu)//简单计算+,-,*,/ { double b=pop_num(nu),a=pop_num(nu); switch(pop_opnd(op))

{

case \'+\':return(a+b);break;

case \'-\':return(a-b);break;

case \'*\':return(a*b);break;

case \'/\':return(a/b);break;

} } void result(opnd *op,num *nu)//计算结果

{ char str2[MAXSIZE]=\"\",str3[2]=\"0\"; char *ps=expr[i].expstr; initstack(op);//初始化栈

initstack(nu); push_opnd(op,\'=\');

数据结构课程设计

while(!((*ps==\'=\')&&(get_opnd(op)==\'=\')))//检查是表达式和操作码是否到尾

if(change_opnd(*ps)==-1)//操作数处理

{

while(change_opnd(*ps)==-1)

{

strncpy(str3,ps,1);//数字字符一个个取出放在str2

strcat(str2,str3);

ps++;

}

push_num(nu,change_num(str2));

strcpy(str2,\"\");

}

else //操作码处理

{

switch(procede(get_opnd(op),*ps))

{

case \'

case \'=\':pop_opnd(op);break;

case \'>\':push_num(nu,caculate(op,nu));continue;break;

}

if(*ps==\')\'&&get_opnd(op)==\'=\')

{

ps++;

continue;

}

if(*ps==\'=\'||get_opnd(op)==\'=\')

continue;//表达式和操作码有一个到尾,则跳出继续循环

ps++;

}

expr[i].result=get_num(nu);

printf(\"\\n\\t

表达式:%s\\t计算结果:%lf\\n\",expr[i].expstr,expr[i].result);

printf(\"\\t--\\n\");

i++;//表达式个数加1;

}

void check()//显示计算结果

{ for(int n=0;n

{

printf(\"\\n\");

printf(\"\\t%d \\n\",n+1);

数据结构课程设计

printf(\"\\t

表达式:%s\",expr[n].expstr);

printf(\"\\t计算结果:%.2lf\\n\",expr[n].result);

if(expr[n].expstr[0]==\'#\')break;//只显示当次计算的记录

} printf(\"\\t--\\n\"); }

void save()//保存计算结果

{ FILE *fp; int m,n; if((fp=fopen(\"calculate.dat\",\"ab\"))==NULL)//创建文件

{

printf(\"cannot open file\\n\");

return;

} if(expr[i-1].expstr[0]==\'#\')//不能重复保存

{

printf(\"*提醒:记录已保存过,不需要再次保存。\\n\");

return;

} for(n=i;n>0;n--)//记录最后一个#号位置,即未保存的结果的开始位置,重复保存只会追加

if(expr[n-1].expstr[0]==\'#\')

break; strcpy(expr[i].expstr,\"#表达式个数:\");//每次保存都统计计算次数

expr[i].result=i-n; i++; for(m=n;m

if(fwrite(&expr[m],sizeof(struct expreion),1,fp)!=1)//将表达式和计算结果存到文件中

printf(\"file write error\\n\\n\"); fclose(fp); printf(\"*提醒:计算记录已经保存\\n\\n\"); }

void load()//显示所有计算记录

{ int m; expreion e[N]; FILE *fp; printf(\"\\n\"); if((fp=fopen(\"calculate.dat\",\"rb\"))==NULL)//空文件

{

printf(\"\\t--\\n\");

printf(\"*提醒:没有记录信息,请进行计算并保存信息:\\n\\n\");

21

数据结构课程设计

return;

}

for(m=0;fread(&e[m],sizeof(struct expreion),1,fp);m++)//按照expreion结构一个个读取

{

printf(\"\\t%d \\n\",m+1);

printf(\"\\t

表达式:%s\\t计算结果:%.2lf\\n\",e[m].expstr,e[m].result);

if(e[m].expstr[0]==\'#\')//控制输出不同次计算的记录

{

m=-1;

printf(\"\\n\");

}

} printf(\"\\t--\\n\"); fclose(fp); printf(\"\\n\"); } void help() { printf(\"\\t|

|\\n\"); printf(\"\\t|

1、请用户正确输入表达式,不得出现非法字符及重复出现。|\\n\"); printf(\"\\t|

2、表达式以 “=”号结尾, 负数用(0-X)形式表示。

|\\n\"); printf(\"\\t|

3、请用户及时保存计算结果,否则计算结果会被清除。

|\\n\"); printf(\"\\t|

|\\n\");

} //void start(opnd *op,num *nu);

void start2(opnd *op,num *nu)//第二层计算选择菜单

{ void start(opnd *op,num *nu); char r; while(1)

{

printf(\"\\t*************************计算表达式的值**********************\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

一、查看本次计算记录,请输入\"r\"或\"R\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

二、保存本次计算记录,请输入\"s\"或\"S\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

三、查看所有计算记录,请输入\"l\"或\"L\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

四、回到主菜单,

请输入\"E\"或\"e\"

***\\n\");

22

数据结构课程设计

printf(\"\\t***

***\\n\");

printf(\"\\t*************************************************************\\n\");

printf(\"\\t请输入: \");

scanf(\"%s\",&r);

if(r==\'r\'||r==\'R\')

check();

else

if(r==\'s\'||r==\'S\')

save();

else

if(r==\'l\'||r==\'L\')

load();

else

{

i=0;

start(op,nu);

}

} } void start(opnd *op,num *nu)//程序主导

{

char ch,c,g;

g=\'Y\';

printf(\"\\t*************************计算表达式的值**********************\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

一、计算式子,请输入\"Y\"或\"y\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

二、查看记录,请输入\"l\"或\"L\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

三、清空记录,请输入\"C\"或\"c\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t***

四、退出程序,请输入\"E\"或\"e\"

***\\n\");

printf(\"\\t***

***\\n\");

printf(\"\\t*************************************************************\\n\");

printf(\"\\t请输入:\");

scanf(\"%s\",&c);

getchar(ch);

if(c==\'l\'||c==\'L\')

{

load();

start(op,nu);

}

else

if(c==\'Y\'||c==\'y\')

23

数据结构课程设计

{

while(1)

{

if(g==\'Y\'||g==\'y\')

{

if(make_str())//语法检查

{

printf(\"\\t--\\n\");

result(op,nu);//计算

}

}

else

{

printf(\"\\n\\t*提醒:计算结束!\\n\\n\");

break;

}

printf(\"\\n继续计算,请输入\"Y\"或\"y\",否则按“E”或“e”键结束计算:\");

scanf(\"%s\",&g);

getchar(ch);

}

start2(op,nu);

}

else

if(c==\'C\'||c==\'c\')//清空文件

{

printf(\"\\t--\\n\");

remove(\"calculate.dat\");

printf(\"*提醒:所有记录已经清空。\\n\\n\");

start(op,nu);

}

else{

printf(\"\\n\\t*提醒:结束!\\n\\n\");

exit(0);

} } void main() { system(\"color 1A\"); opnd op;//操作码栈

num nu;//操作数栈

printf(\"\\n\\t ——————————————请注意—————————————\\n\"); help(); start(&op,&nu);//启动程序

}

24

数据结构课程设计

8心得体会

(1)设计中遇到的问题及解决过程

调试过程中出现一些逻辑和语法错误,但是语法错误容易纠正,而 逻辑错误则比较难纠正,需要通过多次调试,找出过程中的漏洞。在设计数值转换时,只有抓住小数点为中界条件,找出整数位数和小数位数;在保存计算记录时,不能重复保存,需要断点。这些问题都是靠仔细分析,逐步琢磨出来的,要勤动手,先设计,后实现。

(2)设计体会和收获。

发现自己也能解决有点复杂的问题,程序设计思想上有了很大的提高,学会了仔细分析问题的关键和辅助功能,在应用上设计程序要符合大众化的思维方式。

(3)因为时间问题,只能做出表达式基本运算,在以后的时间里,我会改善这个计算程序,让它能计算更复杂的表达式,如加上sin,cos时的运算。

9参考文献

【1】.[美] Gary Bronson 著,刘勇译.Programming Development and Design Using C++, Second Edition(C++程序开发与设计,第2版).北京:人民邮电出版社,2002 【2】.王萍.C++面向对象程序设计.北京:清华大学出版社.2002 【3】.罗建军等.C++程序设计教程(第2版).北京:高等教育出版社,2004 【4】.谭浩强.C++程序设计.北京:清华大学出版社.2004 【5】.黄维通.Visual C++面向对象与可视化程序设计(第2版).北京:清华大学出版社,2007 【6】.张基温.C++程序设计基础.北京:高等教育出版社,2001 【7】.刁成嘉.面向对象C++程序设计.北京:机械工业出版社,2004 【8】.郑莉等.C++语言程序设计(第2版).北京:清华大学出版社,2001

25

数据结构 教学计划
《数据结构 教学计划.doc》
将本文的Word文档下载到电脑,方便编辑。
推荐度:
点击下载文档
相关专题
点击下载本文文档