资源描述
数据结构顺序表实验报告优质资料
(可以直接使用,可编辑 优质资料,欢迎下载)
洛阳理工学院实验报告
系别
计算机
班级
学号
姓名
课程名称
数据结构
实验日期
10/23
实验名称
顺序表的基本操作
成绩
实验目的:
熟悉掌握线性表顺序存储结构,掌握与应用顺序表的查找、插入、删除等基本操作算法,训练和提高结构化程序设计能力及程序调试能力。
实验条件:
计算机一台,Visual C++6.0
实验内容:
1. 问题描述
以顺序表为存储结构实现以下基本操作:
(1) 在第i个元素前插入一个新元素。
(2) 查找值为x的某个元素。若成功,给出x在表中的位置;不成功给出提示信息。
(3) 删除第i个元素,若成功,给出提示信息并显示被删元素的值;不成功给出失败的提示信息。
2. 数据结构类型定义
typedef struct
{ ElemTypeelem[MAXSIZE];
Intlast;
}SeqList;
3. 模块划分
(1)创建顺序表输入函数:void Input(SeqList *L,int n);
(2)创建顺序表输出函数:void Output(SeqList *L);
(3)创建顺序表的内容查找函数:int Locate(SeqList L,ElemType e);
(4)创建顺序表的插入函数:int InsList(SeqList *L,int i,ElemType e);
(5)创建顺序表的删除函数: int DelList(SeqList *L,int i,ElemType *e);
(6)主函数:void main()
4. 详细设计
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define OK 1
#define ERROR -1
#define TRUE 1
#define FALSE 0
#define ElemType int
#define MAXSIZE 100 //最大长度
typedef struct
{ ElemType elem[MAXSIZE];
int last;
}SeqList;
void Input(SeqList *L,int n) //输入函数
{ int i;
printf("请输入线性表的各元素值:\n");
for(i=0; i<n; i++)
scanf("%d",&L->elem[i]);
}
void Output(SeqList *L) //输出函数
{ int i;
for(i=0; i<=L->last; i++)
printf("%2d,",L->elem[i]);
printf("\n");
}
int Locate(SeqList L,ElemType e)//内容查找函数
{ int i;
i=0;
while((i<=L.last)&&(L.elem[i])!=e)
i++;
if(i<=L.last)
return(i+1); //返回序号
else
return(-1);
}
int InsList(SeqList *L,int i,ElemType e)//插入数据
{ int k;
if((i<1) || (i>L->last+2)) /*首先判断插入位置是否合法*/
{ printf("插入位置不合法\n");
return(ERROR);
}
if(L->last>= MAXSIZE-1)
{ printf("表已满无法插入");
return(ERROR);
}
for(k=L->last;k>=i-1;k--) //为插入元素而移动位置
L->elem[k+1]=L->elem[k];
L->elem[i-1]=e; //第i个元素的下标为i-1
L->last++;
return(OK);
}
int DelList(SeqList *L,int i,ElemType *e) //删除函数
/*在顺序表L中删除第i个数据元素,并用指针参数e返回其值。i的合法取值为1≤i≤L.last+1 */
{ int k;
if((i<1)||(i>L->last+1))
{ printf("删除位置不合法!\n");
return(ERROR);
}
*e = L->elem[i-1]; /* 将删除的元素存放到e所指向的变量中*/
for(k=i; k<=L->last; k++)
L->elem[k-1] = L->elem[k]; /*将后面的元素依次前移*/
L->last--;
return(TRUE);
}
void main()//主函数
{SeqList l,*la;
int p,q,r,k,j ,m,num;
printf("请输入线性表的长度:");
scanf("%d",&r);
l.last = r-1;
la=&l;
Input(la,la->last+1);
Output(la);
//按内容查找元素
printf("请输入要查找的元素值:\n");
scanf("%d",&q);
p=Locate(l,q);
if(p == -1)
printf("在此线性表中没有该元素! \n");
else
printf("该元素在线性表中的位置为:%d \n",p);
//插入元素 (在i处插入元素e)
printf("请输入要插入的位置:\n");
scanf("%d",&k);
printf("请输入要插入的元素值:\n");
scanf("%d",&j);
InsList(la,k,j); //调用插入函数
Output(la);
//删除元素 删除第i个元素
printf("请输入需要删除的元素的位置:\n");
scanf("%d",&m);
DelList(la,m,&num);
printf("删除成功,删除的元素为%d",num);
printf("\n");
Output(la);
}
5.测试数据及结果
实验总结:
经过调试与测试,实验结果与测试预期一致。顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
第10章实验
实验名称:考试日程安排与成绩统计
实验类型:综合性性实验
班级:20210611
学号:2021061118
姓名:郭鑫
1. 问题描述
①问题描述
l 现要安排考试的考表(即考试日程表),假设共有10个班的学生,要安排10门必修课程的考试,必修课程是以班级来确定的,每个班各有3门必修课,因此各班的考试科目是不相同的;安排考表的原则是:相同课程采用统一的试卷,因此同一门课程的考试必须在相同时间进行,同一个班所修的科目必须安排在不同的时间进行考试,以避免考试时间的冲突。并要求全部考试的日程尽可能短。
l 要求对考试结果做统计和排序。假设分别以编号0,1,2,3,4,5,6,7,8,9代表10门要考试的课程,以B1,B2,B3,B4,B5,B6,B7,B8,B9,B10代表10个班,每个人的信息包括学号、姓名、班级、各门考试课程成绩、三门课程总成绩,每个班的学生人数自行设定。要求设计一个简单的考试成绩的查询统计系统实现以下功能:
² 显示学生考试情况-按考试总分从高到底输出全体学生的信息。-按照从B1到B10的班级顺序,分班级按照考试总分从高到底的顺序输出各班学生的信息。-输出指定班的学生考试成绩信息。
² 统计学生考试成绩-按总成绩统计出90分以上、80~89分、70~79分、60~69分、60分以下各分数段的人数,并按总分从高到低分段输出。-根据指定的某们课程的成绩,统计出上述各分数段的人数,并按分数从高到低分段输出。-统计并输出指定班级中总成绩或某一门课成绩的各分数段人数和每个人具体的信息。
² 查找学生成绩-查找总分或某一门课程成绩的指定分数段的人数及学生的详细信息。-查找指定班级中总分或某一门课程成绩属于某分数段的学生详细信息。-查找指定学生(例如给定学号)的具体信息,包括:姓名、班级、各科分数、总分数等。
②求解方法说明
l 考试日程安排问题。
² 该问题实际上是对若干元素进行子集划分的问题,要求所划分的每个子集中的元素没有“考试冲突”关系。
² 假设各个班的考试课程分别为:(1,4,8),(1,3,7),(8,2,4),(1,0,5),(2,6,9),(3,0,8),(4,5,9),(2,9,7),(6,0,3),(5,6,9)。根据题中考试安排原则,各个班要进行的考试课程可以抽象为“考试冲突关系”,归纳各个班的考试课程可以整理得到考试冲突关系:R={(1,4),(1,8),(4,8),(1,3),(1,7),(3,7),(8,2),(2,4),(1,0),(1,5),(0,5),(2,6),(2,9),(6,9),(3,0),(0,8),(3,8),(4,5),(5,9),(4,5),(2,7),(9,7),(6,0),(6,3),(5,6)}。显然,“考试冲突”关系R的每个有序对中的两门课程不能安排在同一时间考试,据此可以将10门课划分为若干个考试时间没有冲突的子集,并且使考场的场次尽量少,使得整个考试时间尽可能短。
² 上述子集划分问题可以用对集合中的元素逐个“筛选”的办法来解决。首先将集合的第1个元素置为第1个子集,再逐个检查集合中的其余元素是否和第1个元素有考试冲突,若不存在考试冲突,则将其加入到第1个子集中,继续检查集合中的其余元素,凡是不与第1个子集中的元素冲突的元素都逐个将其加入到其中;接着按同样的方法“筛选”出若干没有考试冲突的元素构成第2个子集,…,该过程一直到集合中的全部元素都分到某个子集中结束。得到的每一个子集中的课程就是可以安排在同一时间考试的课程。不同子集的课程则要安排在不冲突的时间考试。
l 考试分数的统计与排序
² 考试成绩输出
ü 每个学生的信息记录数据项应包括:学号、姓名、班级、课程1、课程2、…、课程10、总成绩。
ü 按总分高低输出所有学生信息时,应该以总成绩为关键字从高分到低分对所有的学生记录进行排序,排序方法自行选定,然后依次输出各个记录。
ü 按照班级顺序和总分高低输出各班学生信息时,要对学生记录进行多关键字排序,首先以总成绩为关键字从高分到低分对所有的学生记录进行排序,然后再以班号为关键字对全部学生记录排序,再输出结果。
² 统计成绩统计各分数段的人数,要求由用户输入,具体要求可以有:
ü 按照总成绩统计各分数段的人数,并输出各分数段的学生记录,即在统计一个分数段的人数过程中,要输出满足查找条件的学生记录,再输出统计的结果。
ü 指定某一门课程,统计各分数段的人数并输出各分数段的学生记录。
ü 对指定班级中总成绩或指定课程成绩做各分数段人数的统计,也要输出各分数段的学生记录。
² 查找成绩查找要求由用户输入,可以输入以下条件:
ü 查找指定分数项(总分或某一门课程)的某分数段的学生信息,输出查找结果。
ü 查找指定班级、指定分数项的某分数段的学生信息,输出查找结果。
ü 查找指定学生(给定学号)的具体信息,输出查找结果。
③算法提示
l 考试场次的划分——“无考试冲突”子集划分的算法思路。 为了把10门课程划分为时间上不冲突的若干场考试,可以利用一个循环队列来实现求解方法中说明的“筛选”过程。 首先定义一个循环队列,再把10门课程的编号从小到大依次加入到循环队列中,然后重复下列步骤:
ü 队头元素出队并作为当前子集的第1个元素。
ü 队头元素继续依次出队,每出队一个队头元素都要检查与当前子集中的元素是否有“考试冲突”;如果没有冲突,则将其加入到当前子集中,否则将其重新加入队列中,等待以后加入新子集的机会。
ü 比较刚出队元素与前一出队元素编号。因为队列中原有的元素是以编号从小到大的顺序排列的,重新入队的元素编号一定小于它的前一元素,所以一旦发现目前出队的元素编号小于前一个出队的元素,就可以断定当前的“考试冲突”子集已经构建完,队列中剩余元素应该构建新的子集。为此,在当前的队头元素出队前,要先记下刚刚出队的元素,以便判断当前出队的元素是否要开始构建一个新子集。
重复上述步骤一直到队列空,则“无考试冲突”子集划分完成。
由上述算法思路可以知道,“无考试冲突”子集的划分过程是一个循环的执行过程,循环中的主要操作是元素出队和判断的操作。判断操作包括出队元素是否可以加入当前子集和是否要开始构建一个新子集两个方面,对后一个判断如前所述,通过比较出队元素与前一个出队元素编号大小可以确定。为了判断出队元素与当前子集中的元素是否有“考试冲突”,可以定义一个二维数组conf[n][n]来表示课程的考试冲突关系矩阵,矩阵中各元素的值根据以下规则确定,若编号为i的课程和编号为j的课程有考试冲突,则置conf[i][j]=1,否则置conf[i][j]=0,考试冲突关系矩阵如图1所示。
0
1
0
1
0
1
1
0
1
0
1
0
0
1
1
1
0
1
1
0
0
0
0
0
1
0
1
1
1
1
1
1
0
0
0
0
1
1
1
0
0
1
1
0
0
1
0
0
1
1
1
1
0
0
1
0
1
0
0
1
1
0
1
1
0
1
0
0
0
1
0
1
1
1
0
0
0
0
0
1
1
1
1
1
1
0
0
0
0
0
0
0
1
0
1
1
1
1
0
0
图1 考试冲突关系矩阵
利用“考试冲突”关系矩阵可以检查出队元素i是否与当前子集中的元素有考试冲突,其方法是:当课程号为j1,j2,…,jk的元素已经在当前子集S中,要判断目前出队的元素i是否可以加入子集S,只要检查“考试冲突”关系矩阵中第i行的元素conf[i][ j1],conf[i][ j2],…conf[i][ jk]的值是否为0即可。如果这些元素的值都为0,表示课程i与子集中的课程没有考试冲突,可以加入其中,否则说明表示课程i与子集中的某些课程有考试冲突,它不能加入该子集中。为了减少在二维数组conf中查找元素的操作,可以定义一个一维数组clash[n]来方便出队元素i是否要加入当前子集的判断,数组clash[n]用于记录出队元素i与当前子集中的元素是否存在考试冲突的信息。每当开始构建一个新子集时,先将数组clash[n]的各元素初始化为0,当有编号为i的课程加入子集时,将“考试冲突”关系矩阵中第i行的各列的值与数组clash的各对应元素的值相加,因而使得数组clash中和编号为i的元素有考试冲突的相应元素的值不再是0,当下一个队头元素j出队时,只要检查数组clash中第j个元素的值是否为0,就可以判断其是否与当前子集中的元素有考试冲突;若数组clash中第j个元素的值不为0,则说明元素j与当前子集中元素存在考试冲突,应将其重新加入队列;若数组clash中第j各元素的值为0,则说明它与当前子集中元素不存在考试冲突,应该将它加入当前子集中,同时要将“考试冲突”关系矩阵中第j行的各列的值与数组clash的各对应元素的值相加,这个过程一直到队列空,则划分无考试冲突子集完成。划分结果可以用一个二维数组来记录各子集中的元素的方式来表示,也可以用一个一维数组来记录每个元素其所属的子集号的方式来表示。上述算法的思路可以描述如下:
建立表示课程考试冲突关系矩阵的二维数组conf[n][n];
定义用于检查当前子集的课程考试冲突信息的数组clash[n];
定义用于记录子集划分结果的数组result[n];
pre=n;//pre用于记录前一个出队元素的编号,初始值置为n以
新建第1个子集
k=0; //k用于记录子集序号
0~9(课程编号)依次入队;
while(队列不空)
{
队头元素i出队;
if(i<pre)//刚出队元素小于前一个出队元素,生成一个新子集
{
k++;
数组clash初始化;
}
if(i可以加入当前子集)//如果刚出队元素与当前子集中的元素
无考试冲突,将其加入当前子集
{
将i加入当前子集,记录i所属子集的序号;
将conf数组第i行各列的值与clash数组对应列的值相加并记入clash中;
}
else //如果刚出队元素与当前子集中的元素有考试冲突,将其重新入队
将i重新加入队列;
pre=i;
}
l 考试成绩统计和排序的实现
ü 按总成绩或按某一门课的成绩统计并输出人数时,应该使各分数段的人数和每个学生的信息清晰的分开。
ü 对全体学生或对某一个班的学生的成绩进行排序时,排序方法可以任意选择。就本实验问题而言,因表长不大采用简单的排序方法就可以达到目的,但为了比较各种常用排序方法性能和适用场合,还可以采用不同的排序方法实现排序。
ü 对多关键字的排序要求,要注意排序方法的稳定性问题。例如,在按总成绩从高分到低分对全体学生进行排序后,再按班级从高分到低分进行排序,此时要求分班级排序时采用的排序方法其动态性能必须是稳定的。同样地,如果在按总成绩从高分到低分排序的基础上,再要求按某一门课的成绩从高分到低分排序,也要求第2层排序一定注意选择动态性能稳定的排序方法。
ü 在实现查找或排序功能时,其查找或排序的依据(指定项)和目标(输出结果)通过提示用户输入来确定。
2. 数据结构设计
typedef int KeyType;
typedef char InfoType[10];
typedef struct /*记录类型*/
{
KeyType key; /*关键字项*/
InfoType data; /*其他数据项,类型为InfoType*/
} RecType
3. 算法设计
#include<iostream>
using namespace std;
#define MAXE 20/*线性表中最多元素个数*/
typedef int KeyType;
typedef char InfoType[10];
typedef struct /*记录类型*/
{
KeyType key; /*关键字项*/
InfoType data; /*其他数据项,类型为InfoType*/
} RecType;
void SelectSort(RecType R[],int n)/*直接选择排序算法*/
{
int i,j,k,l;
RecType temp;
for (i=0;i<n-1;i++) /*做第i趟排序*/
{
k=i;
for (j=i+1;j<n;j++) /*在当前无序区R[i..n-1]中选key最小的R[k] */
if (R[j].key<R[k].key)
k=j; /*k记下目前找到的最小关键字所在的位置*/
if (k!=i) /*交换R[i]和R[k] */
{
temp=R[i];R[i]=R[k];R[k]=temp;
}
printf(" i=%d ",i);/*输出每一趟的排序结果*/
for (l=0;l<n;l++)
printf("%2d",R[l].key);
printf("\n");
}
}
int main()
{
int i,k,n=10,m=5;
KeyType a[]={6,8,7,9,0,1,3,2,4,5};
RecType R[MAXE];
for (i=0;i<n;i++)
R[i].key=a[i];
printf("\n");
printf(" 初始关键字 ");/*输出初始关键字序列*/
for (k=0;k<n;k++)
printf("%2d",R[k].key);
printf("\n");
SelectSort(R,n);
printf(" 最后结果 ");/*输出初始关键字序列*/
for (k=0;k<n;k++)
printf("%2d",R[k].key);
printf("\n\n");
system("pause");
}
4.界面设计
程序包含有多个功能,所以,采用菜单,以方便用户进行功能选择。菜单如下:
1:直接插入排序算法验证
2:快速排序算法验证。
3: 直接选择排序算法验证。
4: 退出
5. 运行、测试与分析
1)直接插入排序算法验证
2) 快速排序算法验证。
3)直接选择排序算法验证。
6. 实验收获及思考
这次实验我对选择拍循序,插入排序,快速排序有了更好的理解,以及时间复杂度的问题分析,通过这次实验,我对排序的内容有了更深入的了解。编程技术有了很大的提高
目录
1 选题背景2
2 方案与论证3
2.1 链表的概念和作用3
2.3 算法的设计思想4
2.4 相关图例5
2.4.1 单链表的结点结构5
2.4.2 算法流程图5
3 实验结果6
3.1 链表的建立6
3.2 单链表的插入6
3.3 单链表的输出7
3.4 查找元素7
3.5 单链表的删除8
3.6 显示链表中的元素个数(计数)9
4 结果分析10
4.1 单链表的结构10
4.2 单链表的操作特点10
4.2.1 顺链操作技术10
4.2.2 指针保留技术10
4.3 链表处理中的相关技术10
5 设计体会及今后的改进意见11
参考文献12
附录代码:13
1 选题背景
陈火旺院士把计算机60多年的发展成就概括为五个“一”:开辟一个新时代----信息时代,形成一个新产业----信息产业,产生一个新科学----计算机科学与技术,开创一种新的科研方法----计算方法,开辟一种新文化----计算机文化,这一概括深刻影响了计算机对社会发展所产生的广泛而深远的影响。
数据结构和算法是计算机求解问题过程的两大基石。著名的计算机科学家P.Wegner指出,“在工业革命中其核心作用的是能量,而在计算机革命中其核心作用的是信息”。计算机科学就是“一种关于信息结构转换的科学”。信息结构(数据结构)是计算机科学研究的基本课题,数据结构又是算法研究的基础。
2 方案与论证
2.1 链表的概念和作用
链表是一种链式存储结构,链表属于线性表,采用链式存储结构,也是常用的动态存储方法。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
以“结点的序列”表示线性表称作线性链表(单链表)
单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
因此,查找第 i 个数据元素的基本操作为:移动指针,比较 j 和 i
单链表
1、链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
注意:
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。
2、链表的结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域--存放结点值的数据域
next域--存放结点的直接后继的地址(位置)的指针域(链域)
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
3、头指针head和终端结点指针域的表示
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
注意:
链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
2.2 实验的基本要求(软硬件)
用VC++6.0软件平台,操作系统:Windows XP 硬件:内存要求:内存大小在256MB,其他配置一般就行。
2.3 算法的设计思想
(a)定义一个创建链表的函数,通过该头插法创建一个带头结点的链表,在接下来的链表操作中使用。
(b)定义输出链表的算法 ,遍历结点的指针域判断是否为空,如果不为空则输出其数据域,直到指针域为空为止。
(c)定义一个遍历查找的算法,通过遍历的数据域,分别与要查询的元素进行比较,如果查找到则返回并输出,如入查找失败则返回错误提示信息。
(d)定义插入结点的算法,首先查找指针域为空的结点,并申请空间插入在结点的后边,并且将其指针域置空。
(e)定义删除节点的操作,这个算法用于对链表中某个多余节点的删除工作,其关键在于前驱结点的保留,查找到需删除的结点,将其删除,并将其后继结点连到其前驱结点。
2.4 相关图例
2.4.1 单链表的结点结构
如图2-1所示,为单链表的结点结构示意图:
Data域 Next域
图2-1 单链表的结点结构
2.4.2 算法流程图
如图2-2所示,为此算法流程图:
开始
定义结构体Node
构建各种对链表操作的函数(插入、删除、查找、输出),并写出相应的算法及实现过程
创建一个单链表,用于之前所定义的函数对其进行操作
按要求输出结果
结束
图2-2 算法流程图
3 实验结果
3.1 链表的建立
图 3-1 链表的建立
3.2 单链表的插入
图3- 2单链表的插入
3.3 单链表的输出
图3-3 输出单链表元素
3.4 查找元素
图3-4查找成功
图3-5 查找失败
3.5 单链表的删除
图3-6 删除成功
图3-6 删除失败
3.6 显示链表中的元素个数(计数)
图3-7输出长度
4 结果分析
4.1 单链表的结构
一般情况下,使用链表,只关心链表中结点间的逻辑顺序,并不关心每个结点的实际存储位置,因此通常情况下用箭头来表示链域中的指针,于是链表就可以更直观的画成用箭头链接起来的结点序列,如下图所示:
A
B
C
D
E ^
H
图4-1 单链表的示例图
4.2 单链表的操作特点
4.2.1 顺链操作技术
从“头”开始,访问单链表L中的结点i(p指向该节点)时,由于第i个结点的地址在第i-1个结点(pre指向该结点,为p的前驱)的指针域中存放,查找必须从单链表的“首结点”开始(p=L);通过p=p->next并辅助计数器来实现。
4.2.2 指针保留技术
通过对第i个结点进行插入、删除等操作时,需要对第i-1个结点的指针域进行链址操作(pre->next),因此在处理过程中始终需要维持当前指针p与其前驱指针pre的关系,将这种技术称为“指针保留技术”。
4.3 链表处理中的相关技术
1)单链表与多重链表的差别在于指针域的个数。
2)判断当前结点p是否为表尾。一半链表中,p结点是表尾的条件是:该节点的后继结点为空指针,即p->next==NULL;
3)链表的长度并未显示保存。由于链表是动态生成的结构,其长度要通过顺链查找到表尾得到。因此在处理链表时,往往是以当前处理结点p是否为表尾作为控制条件,而不是长度n作为控制条件。
5 设计体会及今后的改进意见
通过这次实验加深了我对于单链表的进一步了解,了解到了单链表在内存中的存储结构,最重要的是学会了如何运用C语言将单链表的建立,插入、删除、添加等操作。在程序实现中也遇到了一些困难,在单链表初始化时,使用了0作为结束输入符,导致单链表不能存储数据0;单链表中只能存储相同类型的数据,在存储不同类型的数据时需要改变输入结束标志,程序通用性比较差。
在进行程序设计的时候没有考虑好删除和查找的方式,只进行了输入元素的查找和删除,而且进行链表的插入时,只考虑了头插法在结尾插入,而没有考虑输入结点插入等,程序的灵活性比较低。
通过这次课程设计,让我充分认识到数据结构在编写程序方面的重要地位。
不仅仅是单链表的操作,还有栈和队列等特殊的单链表操作,以及其他一些常用的数据结构对于程序的效率和内存使用有很大的帮助。我希望在接下来的学习中收获更多的东西。
参考文献
[1]耿国华.数据结构--用C语言描述[M].北京:高等教育出版社,2021.6.
[2]谭浩强.C程序设计[M].北京:清华大学出版社,2004.6.
附录代码:
结构体定义:
#pragmaonce
#include<stdio.h>
#include<stdlib.h>
enummy_enum
{
_EXIT,
_CREATE,
_INSERT,
_PRINT,
_SEARCH,
_DELETE,
_COUNT,
};
staticint count = 0;
typedefintElemtype;
typedefstructNode/*单链表结构体的定义*/
{
Elemtype data;
structNode *next;
}
Node, *LinkList;
void test();/*测试函数*/
void main_menu();//主菜单函数
void CreatFromHead(LinkList *l);/*头插法建立单链表*/
void Insert(LinkList l);//单链表的插入
void Print(LinkList l);/*单链表的输出*/
int Search(LinkList l, Elemtype e);//查找指定的元素
void Deletelist(LinkList l, Elemtype e);//删除元素
void Count();//计数
void CREATE(LinkList *head);
void INSERT(LinkList *head);
void PRINT(LinkList *head);
void SEARCH(LinkList* head);
void DELET(LinkList *head);
void COUNT();
单链表操作函数:
#define_CRT_SECURE_NO_WARNINGS
#include"linklist.h"
void main_menu()
{
printf("\t 单链表的简单操作\t\t\n\n");
printf("\t 1 单链表的建立\n");
printf("\t 2 单链表的插入\n");
printf("\t 3 单链表的输出\n");
printf("\t 4 单链表的查找\n");
printf("\t 5 单链表的删除\n");
printf("\t 6 单链表的长度\n");
printf("\t 0 退出\n");
}
void CreatFromHead(LinkList *l)/*头插法建立单链表*/
{
Node *s;
int c = 0;
int flag = 1;
*l = (Node*)malloc(sizeof(Node));
if (*l == NULL)
{
printf("申请空间失败!!\n");
return;
}
(*l)->next = NULL;
while (flag)
{
scanf("%d", &c);
if (c != 0)
{
s = (Node*)malloc(sizeof(Node));
if (s == NULL)
{
printf("申请空间失败!!\n");
return;
}
s->data = c;
s->next = (*l)->next;
(*l)->next = s;
count++;
}
else flag = 0;
}
}
void Insert(LinkListl)//单链表的插入
{
int insert = 0;
Node * s = NULL;
printf("请输入需要插入的元素:");
scanf("%d", &insert);
s = (Node*)malloc(sizeof(Node));
if (s == NULL)
{
printf("申请空间失败!!\n");
return;
}
while (l->next != NULL)
{
l = l->next;
}
s->data = insert;
s->next = l->next;
l->next = s;
count++;
}
void Print(LinkListl)/*单链表的遍历*/
{
Node *p;
p = l->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int Search(LinkListl, Elemtypee)//查找指定的元素
{
while ((l != NULL) && (l->data != e))
{
l = l->next;
}
if (l == NULL)
{
return -1;//查找失败
}
else
{
return 1;//查找成功
}
}
void Deletelist(LinkListl, Elemtypee)//删除节点
{
Node *p, *r, *q;
p = l->next; q = l;
while (p != NULL)
{
if (p->data == e)
{
r = p;
展开阅读全文