第2章线性表.docx
- 文档编号:7251897
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:37
- 大小:189.25KB
第2章线性表.docx
《第2章线性表.docx》由会员分享,可在线阅读,更多相关《第2章线性表.docx(37页珍藏版)》请在冰豆网上搜索。
第2章线性表
第2章线性表
教学要点
线性表是一种最基本的数据结构,它的数据元素间具有线性逻辑关系,可以在线性表的任意位置进行插入和删除数据元素的操作。
一个线性表结构可以用顺序存储结构和链式存储结构存储。
本章首先学习线性表逻辑结构的特性,然后讨论以顺序存储结构实现的线性表和以链式存储结构实现的线性表的结点结构和操作实现,分析、比较不同实现的优缺点。
本章在VisualStudio中用lists类库型项目实现有关数据结构的基础类定义,用liststest应用程序型项目实现对这些数据结构的测试和演示程序。
建议本章授课8学时,实验6学时。
2.1线性表的概念及类型定义
线性表(LinearList)是一组具有某种共性的数据元素的有序排列,这些数据元素之间具有顺序关系。
除第一个和最后一个数据元素外,每个元素只有一个前驱元素和一个后继元素,第一个数据元素没有前驱元素,最后一个元素没有后继元素。
线性表中元素的类型可以是数值型或字符串型,也可以是其他更复杂的自定义数据类型。
例如:
●数字表:
个位数字表{0,1,2,…,9}可以看成是一个线性表,数据元素是单个数字,数据元素间是按顺序排列的。
●学生成绩表:
一个班级学生的成绩列表可以看成是一个线性表,数据元素是每个学生的学号、姓名、成绩等信息。
●科研设备信息表:
一个实验室的科研设备信息表可以看成是一个线性表,数据元素是每台设备的编号、类型、名称和保管人等信息。
2.1.1线性表的抽象数据类型
1.线性表的数据元素
当我们讨论线形表时,我们使用抽象数据元素ai表示线性表的数据元素。
线性表是由n(n≥0)个数据元素a0,a1,a2,…,an-1组成的有限序列,记作:
LinearList={a0,a1,a2,…,an-1}
其中,n表示线性表的元素个数,称为线性表的长度。
若n=0,则表中没有元素,我们称之为空表。
若n>0,对于线性表中第i个数据元素ai,有且仅有一个直接前驱数据元素ai-1和一个直接后继数据元素ai+1,而a0没有前驱数据元素,an-1没有后继数据元素。
线性表中的数据元素至少具有一种相同的属性,我们称这些数据元素属于同一种抽象数据类型。
具体设计线形表的物理实现时,ai的数据类型将被具体的数据类型所取代,各元素的类型可以相同,也可以不同。
例如,在C#中的线性表,元素的类型可以是相同的整数int类型、字符char类型或字符串string类型;如果数据元素的类型不相同,则可以用object类来描述它们,以表明它们至少具有某种相同的性质(都是某种类型的对象),因为object类是C#类层次的根,所有其它的类都是由object类派生出来的。
在这个意义上,可以简单地说,线性表中的数据元素具有相同的类型。
线性表有两种存储结构:
顺序存储结构和链式存储结构。
用顺序存储结构实现的线性表称为顺序表(SequencedList),用链式存储结构实现的线性表称为链表(LinkedList)。
2.线性表的基本操作
线性表的数据元素之间具有顺序关系,可以在表中任意位置进行插入和删除数据元素的操作。
线性表的典型操作有:
●Get/Set:
访问。
对线性表中指定位置的数据元素进行取值或置值操作。
●Count:
求长度。
求线性表的数据元素个数。
●Insert:
插入。
在线性表指定位置上,插入一个新的数据元素,插入后仍为一个线性表。
●Remove:
删除。
删除线性表指定位置的数据元素,同时保证更改后的线性表仍然具有线性表的连续性。
●Copy:
复制。
重新复制一个线性表。
●Join:
合并。
将两个或两个以上的线性表合并起来,形成一个新的线性表。
●Search:
查找。
在线性表中查找满足某种条件的数据元素。
●Sort:
排序。
对线性表中的数据元素按关键字的值,以递增或递减的次序进行排列。
●Traversal:
遍历。
按次序访问线性表中的所有数据元素,并且每个数据元素恰好访问一次。
2.1.2C#中的线性表类
1.非泛型线性表类ArrayList
.NETFramework的类库中定义了一个线性表类ArrayList,它定义在System.Collections命名空间中。
ArrayList类提供了一种使用大小可按需动态增加的数组,其数据元素的类型是object类。
插入线性表的数据元素是object对象,所以可以是任意类型对象;获取线性表某元素的数据可用object对象保存,一般需根据要求转化为string或其他类型的对象。
ArrayList类具有如下成员(属性和方法)实现线性表的各种操作:
公共构造函数
ArrayList();//初始化ArrayList类的新实例
ArrayList(ICollectionc);//初始化ArrayList类的新实例,它包含从指定集合复制的元素并且具有与所复制的元素数相同的初始容量。
ArrayList(intcapacity);//初始化ArrayList类的新实例,它具有指定的初始容量。
公共属性
virtualintCount{get;}//返回线性表的长度,即包含的元素数
virtualintCapacity{get;set;}//获取或设置线性表可包含的元素数
virtualobjectthis[intindex]{get;set;}//获取或设置指定索引处的元素
公共方法
virtualvoidInsert(intindex,objectvalue);//将数据元素插入指定位置
virtualintAdd(objectvalue);//将对象添加到表的结尾处
virtualvoidAddRange(ICollectionc);//将集合对象添加到表的结尾处
virtualintIndexOf(objectvalue);//返回给定数据首次出现位置
virtualboolContains(objectitem);//确定某个元素是否在表中
virtualvoidRemove(objectobj);//从表中移除特定对象的第一个匹配项
virtualvoidRemoveAt(intindex);//删除指定位置的数据元素
virtualvoidReverse();//将表中元素的顺序反转
virtualvoidSort();//对表中元素进行排序
2.泛型线性表类List
2.0版C#语言和公共语言运行库(CLR)中增加了泛型(Generics)。
泛型通常与集合一起使用。
.NETFramework2.0版类库提供一个新的命名空间System.Collections.Generic,它包含定义泛型集合的接口和类,泛型集合允许用户创建强类型集合,它能提供比非泛型集合更好的类型安全性和性能。
建议面向2.0版的所有应用程序都使用新的泛型集合类,如List
List
泛型类List
List
公共构造函数
List
List
公共属性
virtualTthis[intindex]{get;set;}//获取或设置指定索引处的元素
公共方法
virtualvoidInsert(intindex,Tvalue);//将数据元素插入指定位置
virtualvoidAdd(Tvalue);//将对象添加到表的结尾处
virtualvoidAddRange(IEnumerable
virtualintIndexOf(Tvalue);//返回给定数据首次出现位置
virtualboolContains(Titem);//确定某个元素是否在表中
virtualvoidRemove(Titem);//从表中移除特定对象的第一个匹配项
下面是几个声明并构造特定类型列表的例子:
List
a.Add(86);a.Add(100);//向列表中添加整型元素
List
s.Add(“Hello”);s.Add(“C#2.0”);//向列表中添加字符串型元素
List
st.Add(newStudent(“200518001”,“王兵”));//向列表中添加学生类型元素
3.0版C#语言增加了“集合初始化器”来方便集合对象的初始化,例如:
List
集合初始化器其实是利用编译时技术对初始化器中的元素进行按序调用Add(T)方法。
【例2.1】创建并初始化ArrayList以及打印出其值。
publicclassSamplesArrayList{
publicstaticvoidMain(){
//CreatesandinitializesanewArrayList.
ArrayListmyAL=newArrayList();
myAL.Add("Hello");myAL.Add("World");myAL.Add("!
");
//DisplaysthepropertiesandvaluesoftheArrayList.
Console.WriteLine("myAL");
Console.WriteLine("\tCount:
{0}",myAL.Count);
Console.Write("\tValues:
");
foreach(objectoinmyAL){
Console.Write("\t{0}",o);
}
Console.WriteLine();
myAL.Sort();
Console.Write("\tSortedValues:
");
for(inti=0;i Console.Write("\t{0}",myAL[i]); } Console.WriteLine(); } } 程序运行结果如下: myAL Count: 3 Values: HelloWorld! SortedValues: ! HelloWorld 【例2.2】以顺序表求解约瑟夫环问题。 约瑟夫环(Josephus)问题: 古代某法官要判决n个犯人的死刑,他使用了一条荒唐的方法,让犯人站成一个圆圈,从第s个人开始数起,每数到第d个犯人,就拉出来处决,然后再数d个,数到的人再处决……直到剩下的最后一个人可以得到赦免。 解决这个问题的直接思路是: 用有n个元素的线性表分别表示n个人,利用取模运算实现环形计数,当某人该出环时,删除表中相应位置的数据元素。 实现这种直接思路的程序为: usingSystem; usingSystem.Collections; publicclassJosephus{ publicstaticvoidMain(string[]args){ JosephusStart(5,1,2); } publicstaticvoidShow(ArrayListalist){ foreach(objectoinalist){ Console.Write(o+""); } Console.WriteLine(); } publicstaticvoidJosephusStart(intn,ints,intd){ //n为总人数,从第s个人开始数起,每次数到d。 ArrayListaRing=newArrayList();//List inti,j,k; for(i=1;i<=n;i++)aRing.Add(i);//n个人依次插入线性表 Show(aRing); i=s-2;//第s个人的下标为s-1,i初始指向第s个人的前一位置 k=n;//每轮的当前人数 while(k>1){//n-1个人依次出环 j=0; while(j j++;//计数 i=(i+1)%k;//取模运算实现环形计数 } Console.WriteLine("out: "+aRing[i]); aRing.RemoveAt(i);//第i个人出环,删除第i个位置的元素 k--;i=(i-1)%k; Show(aRing); } Console.WriteLine("\n{0}isthelastperson",aRing[0]); } } } 程序运行结果如下: 12345 out: 2 1345 out: 4 135 out: 1 35 out: 5 3 3isthelastperson 2.2线性表的顺序存储结构 用顺序存储结构实现的线性表称为顺序表。 线性表的顺序存储结构是用一组连续的存储单元顺序存放线性表的数据元素,数据元素在内存的物理存储次序与它们在线性表中的逻辑次序是一致的,即数据元素ai与其前驱数据元素ai-1及后继数据元素ai+1的位置相邻。 线性表中的数据元素属于同一种类型,因此每个数据元素在内存中占用的空间大小是相同的。 假设每个数据元素占据c个存储单元,第一个数据元素的地址为Loc(a0),则第i个数据元素的地址为: Loc(ai)=Loc(a0)+i×c,i=0,1,2,...,n-1 可见,每个数据元素的地址是该元素在线性表中位置(下标)的线性函数,该地址可以直接由下标计算出来,而且每次地址计算所花费的时间都是相同的。 因此,在顺序存储结构的线性表中,每个数据元素是可以随机访问的。 顺序表的存储结构如图2.1所示。 图2.1线性表的顺序存储结构 2.2.1顺序表的类定义 用C#程序设计语言中的数组可以作为实现顺序表的基础。 下面声明的SequencedList 类声明如下: publicclassSequencedList privateT[]items; privateintcount=0; privateintcapacity=0; …… } 线性表的操作将作为SequencedList类的属性和方法成员予以实现。 SequencedList类的一个实例表示一个线性表。 当我们需要使用一个线性表时,就创建SequencedList类的一个对象,通过对这个对象调用公有(public)的属性和方法访问类中成员或进行相应的操作。 从程序员的角度看,能够使用类的功能即可,不必关心类中的具体设计;另一方面,从类设计的角度看,不需要也不能够向类之外的对象提供直接访问数据成员的功能,所以类中数据成员都设置为私有的(private),对外是不可见的。 这就是类的封装性。 SequencedList类的源代码放在SequencedList.cs文件中,本章将SequencedList等基础类定义在lists命名空间,而将使用这些基础类的测试类定义在liststest命名空间。 2.2.2顺序表的操作 1)顺序表的初始化 使用构造方法创建顺序表对象,为顺序表分配存储空间,并设置顺序表为空状态。 算法如下: //构造空顺序表,分配c个存储单元 publicSequencedList(intc){ capacity=c; items=newT[capacity];//所占用的存储单元个数等于capacity count=0;//此时顺序表长度为0 } //不带参数时,构造具有16个存储单元的空表 publicSequencedList(): this(16){} 重载的构造方法以一个数组的多个元素构造顺序表。 算法如下: //以一个数组的多个元素构造顺序表 publicSequencedList(T[]itemArray){ count=itemArray.Length;//顺序表长度 capacity=count+16; items=newT[capacity]; for(inti=0;i items[i]=itemArray[i]; } } 2)返回顺序表长度 publicintCount{get{returncount;}} 在SequencedList类中将返回顺序表长度的功能定义为类的属性成员,相对于方法成员显得更简洁,方法的调用必须加上括号,而属性的调用无须括号。 在前面的例子中我们也看到,C#用数组对象的Length属性获取数组的存储单元个数,如a.Length返回数组a的元素个数,此时Length后没有括号。 3)判断顺序表的空状态 当count等于0时,顺序表为空状态。 后面将看到,顺序表分配的存储空间可以根据需要而调整调整,编程时一般可以认为系统所提供的可用空间是足够大的,因此不必判断顺序表是否已满。 如果空间已用完,系统无法分配新的存储单元,则产生运行时异常。 //判断顺序表是否空 publicboolEmpty{get{returncount==0;}} 4)获取或设置顺序表的容量 私有数据成员capacity表示顺序表的当前容量,定义公有属性Capacity供外部获取或设置顺序表的容量。 获取顺序表的容量,仅是简单地返回数据成员capacity的当前值。 设置顺序表的新容量,则是依次进行以下操作: 重新分配指定大小的存储空间作为顺序表的“数据仓库”,将原数组中的数据元素逐个拷贝到新数组,并设置capacity的新值。 后面将看到,当count等于capacity时,顺序表当前分配的存储空间已装满数据元素,进行后续的操作前,需要调用Capacity属性重新分配存储空间。 算法如下: publicintCapacity{ get{returncapacity;} set{ capacity=value; T[]copy=newT[capacity];//createnewlysizedarray if(count>capacity)count=capacity; Array.Copy(items,copy,count);//copyoverthearray items=copy;//assignitemstothenewarray } } 5)获取或设置指定位置的数据元素值 就像C#的数组下标从0开始一样,我们用从0开始的索引参数i来指示顺序表的第i个元素。 算法如下: //声明索引器以提供对类的实例进行类似于数组的访问;获得或设置顺序表的第i个数据元素值 publicTthis[inti]{ get{ if(i>=0&&i returnitems[i]; else thrownewIndexOutOfRangeException( "IndexOutOfRangeExceptionin"+this.GetType()); } set{ if(i>=0&&i items[i]=value; }else{ thrownewIndexOutOfRangeException( "IndexOutOfRangeExceptionin"+this.GetType()); } } } 6)查找具有特定值的元素 在线性表中查找具有特定值k的元素的过程为: 从线性表的第一个数据元素开始,依次比较线性表中的数据元素是否等于k,若当前数据元素与k相等,则查找成功;否则继续与下一个数据元素进行比较,当比较完线性表的全部数据元素后仍未找到,则返回查找不成功信息。 上述操作分别用Contains方法和IndexOf方法实现,Contains方法查找成功时返回true,否则返回false。 IndexOf方法查找成功时返回k值首次出现位置,否则返回-1。 算法如下: //查找线性表是否包含k值,查找成功时返回true,否则返回false publicboolContains(Tk){ intj=IndexOf(k); if(j! =-1) returntrue; else returnfalse; } //查找k值在线性表中的位置,查找成功时返回k值首次出现位置,否则返回-1 publicintIndexOf(Tk){ intj=0; while(j k.Equals(items[j])) j++; if(j>=0&&j returnj; else return-1; } 7)在顺序表的指定位置插入数据元素 要想在顺序表的第i个位置上插入给定值k,使得插入后的线性表仍然保持连续性,首先必须将第n-1到第i个位置上的数据元素依次向后移动一个位置,即依次向后移动从an-1到ai的数据元素,空出
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 线性
![提示](https://static.bdocx.com/images/bang_tan.gif)