数据结构编书样张ch2.docx
《数据结构编书样张ch2.docx》由会员分享,可在线阅读,更多相关《数据结构编书样张ch2.docx(24页珍藏版)》请在冰豆网上搜索。
数据结构编书样张ch2
第二章线性表
线性表是一种常见的数据结构。
它有两种存储方方式:
顺序存储和链式存储。
对其进行的主要操作有:
插入、删除、查找和排序等。
2.1线性表的逻辑结构
2.1.1线性表的定义
线性表是一种线性结构的数据结构,数据元素之间是一种线性关系,元素是顺序排列的。
在线性表中,数据元素的类型是相同的。
在实际生活中线性表的例子很多,如学生基本信息表,学生成绩表等。
线性表定义如下:
线性表是由n(n>=0)个,具有相同数据类型的数据元素构成的有限序列,常记为:
A=(a1,a2,…ai-1,ai,ai+1,…an)
其中,A为线性表名,n为线性表的表长,当n=0时,称此线性表为空表。
表中相邻元素之间存在着顺序关系。
在线性有且仅有开始结点与一个终端结点。
2.1.2线性表的基本操作
在第一章中提到,数据结构的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在存储结构上的。
换句话说,某数据结构的一种运算,针对此数据结构采用不同的存储结构,这个运算的实现的具体方法是不同的。
因此,下面的线性表的基本运算是定义在逻辑结构上的,每个运算的具体实现步骤(方法)只有在确定了线性表的存储结构之后才能完成。
线性表上的基本操作有:
(1)构建线性表:
create_List(L)
将线性表中的元素,采用一定的存储结构存放到计算机中,利用计算机语言来实现对线性表的操作。
(2)输出线性表中的元素操作:
out_List(L)
输出线性表中所有的数据元素。
(3)求线性表的长度:
Length_List(L)
求解线性表中数据元素的个数
(4)简单查找:
check_List(L,x),x是给定的一个数据元素。
在表L中查找值为x的数据元素,其结果返回在L中首次出现的值为x的那个元素的序号或地址,称为查找成功;否则,在L中未找到值为x的数据元素,则返回一特殊值表示查找失败。
(5)复杂查找操作:
checkall_List(L,x),x是给定的一个数据元素。
在表L中查找值为x的数据元素,其结果返回在L中所有的值为x的元素的序号或地址。
(6)插入操作:
Insert_List(L,i,x)
在线性表L的第i个位置上插入一个值为x的新元素,插入后表长为原表长加1。
(7)简单删除操作:
delete_List(L,i)
在线性表L中删除第i个数据元素,删除后新表长为原表长减1。
(8)复杂删除操作:
delete_List(L,i,k)
在线性表L中,从第i个数据元素开始,连续删除k个数据元素,删除后修改新表长。
说明:
1.某数据结构上的基本运算,不是它的全部运算,而是一些常用的基本的运算,读者掌握了某一数据结构上的基本运算后,其它的运算可以通过基本运算来实现,也可以直接去实现。
2.在上面各操作中定义的线性表L仅仅是一个抽象在逻辑结构层次的线性表,尚未涉及到它的存储结构,因此每个操作在逻辑结构层次上尚不能用具体的某种程序语言写出具体的算法,而算法的实现只有在存储结构确立之后。
2.2线性表的顺序存储及运算实现
2.2.1顺序表
线性表的顺序存储是指在计算机的内存中用一块连续的地址作为存储空间顺序存放线性表的各元素,这种存储形式的线性表称为顺序表。
计算机的内存中的地址空间是连续的,因此,用物理上的相邻的存储单元来实现逻辑上相邻的数据元素的存放是简单、可行的。
如图2.1所示。
设a1的存储地址为Loc(a1),每个数据元素占d个存储地址,则第i个数据元素的地址为:
Loc(ai)=Loc(a1)+(i-1)*d1<=i<=n
只要知道顺序表首地址和每个数据元素所占地址单元的个数就可求出第i个数据元素的地址,这是顺序表“按序号随机存取”的特点的体现。
在高级程序设计语言中,一维数组在内存中占用的存储空间是一组连续的存储区域,因而,用一维数组来实现线性表的数据元素的存放是再合适不过的。
设用:
data[MAXSIZE]来表示存放线性表的区域,其中MAXSIZE是一个根据实际问题定义的足够大的整数,线性表中的数据元素从data[0]开始依次存放,为了记录当前线性表中的实际元素个数,引入了一个变量length来存放线性表中数据元素的个数(表长)。
因此,当表为空时length为0。
0
1
…
i-1
i
…
n-1
...MAXSIZE1-1
data
a1
a2
…
ai-1
ai
ai+1
…
an
…
图2.1线性表的顺序存储示意图
通常将data数组和length封装成一个结构体作为顺序表的类型:
typedefstruct
{datatypedata[MAXSIZE];
intlength;
}SeqList;
定义一个顺序表的语句:
SeqListL;
这种线性表如图2.2所示。
表长为L.length,线性表中的数据元素a1至an分别存放在L.data[0]至L.data[L.length-1]中。
2.2.2顺序表上基本运算的实现
1.顺序表的构建create_List()
顺序表的构建就是将线性表中的元素依次存放到data[MAXSIZE]数组中,并将数据元素的个数赋给length。
算法如下(为了简单起见,假设数据元素的类型是int类型):
#defineMAXSIZE100
/*定义顺序存储类型*/
typedefstruct
{intdata[MAXSIZE];/*存放线性表的数组*/
intlength;/*length是线性表的长度*/
}SeqList;
/*构建顺序表*/
SeqListcreate_List()
{SeqListL;
inti,n,x;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&L.data[i-1]);
L.length=n;
return(L);}
算法2.1
设调用函数为主函数,主函数对构建函数的调用如下:
main()
{SeqListL;
L=create_List();
...
}
2.输出操作out_List(SeqListL)
输出线性表中的元素操作:
Out_List(L),具体做法:
先判断顺序表中表的长度,若L.length为0,数组中没有元素,输出错误;若表长L.length不为0,则将数组中的元素(数组下标区间为[0,L.length-1])依次输出。
out_List(SeqListL)
{inti;
printf("的chushuju\n");
for(i=0;i<=L.length-1;i++)
printf("%d",L.data[i]);
}
3.求线性表的表长Length_List(SeqListL)
将顺序表中的数据元素的个数求解出来。
intLength_List(SeqListL)
{return(L.length);
}
4.简单查找check_List(SeqListL,intx)
在顺序表的数组中,若存在一个或者多个数据元素为x,则输出第一个x的位置,若顺序表中没有x,则输出一个特殊的位置。
intcheck_List(SeqListL,intx)
{intj;
scanf("%d",&x);j=0;
while((j<=L.length-1)&&(L.data[j]!
=x))
j++;
if(j=L.length)
return(-1);
else
return(j+1);
}
5.复杂查找checkall_List(SeqListL,intx)
在顺序表的数组中,存在一个或者多个数据元素为x,则依此输出x的位置。
checkall_List(SeqListL,intx)
{intj=0,k=0;
scanf("%d",&x);
while(j<=L.length-1)
{if(L.data[j]==x)
printf(“%d”,j+1);
j++;}
}
6插入运算Insert_List(L,i,x)
线性表的插入是指在表的第i个位置上插入一个值为x的新元素,插入后使原表长为n的表:
(a1,a2,...,ai-1,ai,ai+1,...,an)
成为表长为n+1表:
(a1,a2,...,ai-1,x,ai,ai+1,...,an )。
i的取值范围为1<=i<=n+1。
顺序表上完成这一运算则通过以下步骤进行:
(1)将ai~an顺序向下移动,为新元素让出位置;
(2)将x置入空出的第i个位置;
(3)修改last指针(相当于修改表长),使之仍指向最后一个元素。
算法如下:
Insert_List(SeqListL,inti,intx)
{ intj;
if(L.length==MAXSIZE)
{printf("表满");
exit(0);}/*表空间已满,不能插入*/
if(i<1||i>L.length+1) /*检查插入位置的正确性*/
{printf("位置错");exit(0);}
for(j=L.length;j>=i;j--)
L.data[j]=L.data[j-1];/*结点移动*/
L.data[i-1]=x; /*新元素插入*/
L.length++;
}
注意以下问题:
(1)顺序表中数据区域有MAXSIZE个存储单元,所以在向顺序表中做插入时先检查表空间是否满了,在表满的情况下不能再做插入,否则产生溢出错误。
(2)要检验插入位置的有效性,这里i的有效范围是:
1<=i<=n+1,其中n为原表长。
(3)注意数据的移动方向。
a1
a2
…
ai-1
ai
ai+1
…
an
…
a1
a2
…
ai-1
x
ai
ai+1
…
an
…
0
1
i-2
i-1
i
n-1
MAXSIZE-1
插入前插入后
图2.3顺序表中的插入
插入算法的时间性能分析:
顺序表上的插入运算,时间主要消耗在了数据的移动上,在第i个位置上插入x,从ai到an都要向下移动一个位置,共需要移动n-i+1个元素,而i的取值范围为:
1<=i<=n+1,即有n+1个位置可以插入。
设在第i个位置上作插入的概率为Pi,则平均移动数据元素的次数:
设:
Pi=1/(n+1),即为等概率情况,则:
因此,在顺序表上做插入操作需移动表中一半的数据元素,时间复杂度为O(n)。
7.简单删除操作:
delete_List(L,i)
线性表的删除运算是指将表中第i个元素从线性表中去掉,删除后使原表长为n的线性表:
(a1,a2,...,ai-1,ai,ai+1,...,an)
成为表长为n-1的线性表:
(a1,a2,...,ai-1,ai+1,...,an)。
i的取值范围为:
1<=i<=n。
顺序表上完成这一运算的步骤如下:
(1)将ai+1~an顺序向上移动。
(2)修改last指针(相当于修改表长)使之仍指向最后一个元素。
a1
a2
…
ai-1
ai+1
an
…
0
a1
1
a2
…
i-2
ai-1
i-1
ai
i
ai+1
...
n-1
an
…
MAXSIZE-1
删除前删除后
图2.4顺序表中的删除
算法如下:
intdelete_List(SeqListL,inti)
{intj;
if(i<1||i>L.length)/*检查空表及删除位置的合法性*/
{printf("不存在第i个元素");return(0);}
for(j=i;j<=L.length;j++)
L.data[j-2]=L.data[j-1];/*向上移动*/
L.length--;
return
(1);/*删除成功*/
}
注意以下问题:
(1)删除第i个元素,i的取值为1<=i<=n,否则第i个元素不存在,因此,要检查删除位置的有效性。
(2)当表空时不能做删除,且给的i过大,超过L.length时,也不能做删除条件(i<1||i>L.length)也包括了对表空的检查。
(3)删除ai之后,该数据已不存在,如果需要,先取出ai,再做删除。
删除算法的时间性能分析:
与插入运算相同,其时间主要消耗在了移动表中元素上,删除第i个元素时,其后面的元素ai+1~an都要向上移动一个位置,共移动了n-i个元素,所以平均移动数据元素的次数:
在等概率情况下,pi=1/n,则:
在顺序表上作删除运算时大约需要移动表中一半的元素,该算法的时间复杂度为O(n)。
8复杂删除操作:
delete_List(L,i,k)
在线性表L中,从第i个数据元素开始,连续删除k个数据元素,删除后修改新表长。
方法是:
首先判断i的合法性;其次求解出区间[i,n]中包含的元素个数len;比较len与k的
大小,删除并修改表的长度。
算法如下:
SeqListDeleteb(SeqListL,inti,intk)
{intlen,j;
if(i>L.length||i<1)
printf("非法位置!
");
else
{len=L.length-i+1;
if(k>=len)
L.length=i;
else
{for(j=i+k;j<=L.length;j++)
L.data[j-k-1]=L.data[j-1];
L.length=L.length-k;
}
}
return(L);
}
2.2.3顺序表简单应用举例
例2.1有顺序表A和B,其元素均按从小到大的升序排列,编写一个算法将它们合并成一个顺序表C,要求C的元素也是从小到大的升序排列。
算法思路:
依次扫描通过A和B的元素,比较当前的元素的值,将较小值的元素赋给C,如此直到一个线性表扫描完毕,然后将未完的那个顺序表中余下部分赋给C即可。
C的容量要能够容纳A、B两个线性表相加的长度。
算法如下:
merge(SeqListA,SeqListB,SeqListC)
{inti,j,k;
i=0;j=0;k=0;
while(i<=A.length-1&&j<=B.length-1)
if(A.data[i]{C.data[k]=A.data[i];k++;i++;}
else
{C.data[k]=B.data[j];k++;j++;}
while(i<=A.length-1)
{C.data[k]=A.data[i];k++;i++}
while(j<=B.length-1)
{C.data[k]=B.data[j];k++;j++}
C.length=k-1;
}
算法的时间性能是O(m+n),其中m是A的表长,n是B的表长。
2.2.4顺序表复杂应用举例
构建一学生成绩信息表(学号,姓名,性别,英语,数学,数据结构,简介)。
编写相关算法来实现:
(1)创建学生信息;
(2)分别根据学号,姓名进行查找相关学生信息;
(3)根据学号,修改相关学生的信息;
(4)在信息表中插入一新学生的信息;
(5)根据学号,姓名删除相关学生信息;
(6)输出信息表中的学生信息。
主要参考算法(完整算法见实践教材与配套光盘):
#defineSIZE4
#defineM100
#defineN10
#defineNU200
#defineflag-1
typedefstruct
{intxuehao;
charname[N];
charsex[N];
inteng,math,ds;
charjianjie[NU];
}stu;
typedefstruct
{studata[M];
intlen;
}student;
staticstudentL;
staticintn;
1构建学生信息库
createdatabase()
{
inti;
printf("请输入要创建的学生总数\n");
scanf("%d",&n);
for(i=1;i<=n;i++)
{printf("第%d个学生的基本信息\n",i);
printf("请输入学号\n");
scanf("%d",&L.data[i-1].xuehao);
printf("请输入姓名\n");
scanf("%s",L.data[i-1].name);
printf("请输入性别\n");
scanf("%s",L.data[i-1].sex);
printf("请输入英语成绩\n");
scanf("%d",&L.data[i-1].eng);
printf("请输入数学成绩\n");
scanf("%d",&L.data[i-1].math);
printf("请输入数据结构成绩\n");
scanf("%d",&L.data[i-1].ds);
printf("请输入注释\n");
scanf("%s",L.data[i-1].jianjie);
}
L.len=n;
}
2查找信息
Search()
{
intc;
printf("\n1:
查询学号");
printf("2:
查询姓名");
printf("3:
退出\n");
getchar();
printf("\n选择:
");
scanf("\n%d",&c);
switch(c)
{
case1:
Search_xuehao();break;
case2:
Search_name();break;
case3:
break;
default:
printf("输入有错!
\n");
}
}
/*查询学号*/
Search_xuehao()
{
intj=1,xh;
printf("请输入要查询的学号:
\n");
scanf("%d",&xh);
while(L.data[j-1].xuehao!
=xh&&j<=L.len)
j++;
if(L.data[j-1].xuehao==xh)
{printf("%d",L.data[j-1].xuehao);
printf("%s",L.data[j-1].name);
printf("%s",L.data[j-1].sex);
printf("%d",L.data[j-1].eng);
printf("%d",L.data[j-1].math);
printf("%d",L.data[j-1].ds);
printf("%s\n",L.data[j-1].jianjie);
}
else
printf("没有此学生!
");
}
/*查询姓名*/
Search_name()
{
intj=1;
charname[N];
printf("输入要查询的姓名:
\n");
scanf("%s",name);
while(strcmp(L.data[j-1].name,name)&&jj++;
if(!
strcmp(L.data[j-1].name,name))
{
printf("%d",L.data[j-1].xuehao);
printf("%s",L.data[j-1].name);
printf("%s",L.data[j-1].sex);
printf("%d",L.data[j-1].eng);
printf("%d",L.data[j-1].math);
printf("%d",L.data[j-1].ds);
printf("%s\n",L.data[j-1].jianjie);
}
else
printf("没有此学生!
");
}
3修改信息
Update()
{
intj,i;j=1;
printf("输入要修改的学号:
\n");
scanf("%d",&i);
while(L.data[j-1].xuehao!
=i)
j++;
printf("%d",L.data[j-1].xuehao);
printf("%s",L.data[j-1].name);
printf("%s",L.data[j-1].sex);
printf("%d",L.data[j-1].eng);
printf("%d",L.data[j-1].math);
printf("%d",L.data[j-1].ds);
printf("%s\n",L.data[j-1].jianjie);
printf("信息修改为:
\n");
printf("请输入学号\n");
scanf("%d",&L.data[j-1].xuehao);
printf("请输入姓名\n");
scanf("%s",L.data[j-1].name);
printf("请输入性别\n");
scanf("%s",L.data[j-1].sex);
printf("请输入英语成绩\n");
scanf("%d",&L.data[j-1].eng);
printf("请输入数学成绩\n");
scanf("%d",&L.data[j-1].math);
printf("请输入数据结构成绩\n");
scanf("%d",&L.data[j-1].ds);
printf("请输入注释\n");
scanf("%s",L.data[j-1].jianjie);
printf("修改后为:
\n");
printf("%d",L.data[j-1].xuehao);
printf("%s",L.data[j-1].name);
printf("%s",L.data[j-1].sex);
printf("%d",L.data[j-1].eng);
printf("%d",L.data[j-1].math);
printf("%d",L.data[j-1].ds);
printf("%s\n",L.data[j-1].jianjie);
}
4插入信息
Insert()
{
inti=L.len,j;
printf("插入学生的基本信息\n");
prin