线性表是数据结构非常重要的一部分,今天我们就来了解一下什么是线性表,线性表干什么用的以及线性表的经典案例,希望能够帮助到大家。
什么是线性表?
了解之前,先简单介绍一下前驱和后继。其实前驱就是一元素(非首尾)的前一元素,后继就是该元素(非首尾)的后一元素。
线性表是存在一个没有前驱的“头”和没有后继的“尾”,其余数据元素都有前驱和后继。这么说大家可能有点懵,什么头尾的。举一个例子,幼儿园小朋友表演节目,每个人都手拉着手呈直线状,最前面的小朋友和最后面的小朋友有一只手空着,最前面的小朋友没有“前驱”,最后面的小朋友没有后继,其他小朋友俩只手都有小朋友牵,这就可以看作是线性表。
标准一点说:
线性表是n(n>=0)个同质元素的有限序列,每个元素有唯一的前驱和唯一的后继,首元素只有后继,尾元素只有前驱,n为0时是空表。n叫做线性表的长度。
抽象数据类型线性表定义如下
线性表的基础操作
- InitList(&L)初始化:构造一个空的线性表L。
- DestroyList(&L)销毁:销毁一个业已存在的线性表L。
- ClearList(&L) 清空:将一业已存在的线性表L重置为空表。
- ListEmpty(L) 判表空:若L为空表,则返回TRUE;否则返回 FALSE .
- ListLength(L)求长度:对给定的线性表L,返回线性表L的数据元素的个数。
- GetElem(L,i,&e) 对给定的线性表L,取第i个数据元素。 I≤i≤Length(L)-1),用e返回L中第i个数据元素的值。
- LocateElem(L,e,compareO)定位 返回L中第一个与e满足关系 compare(0)的数据元素的位序,若这种数据元素不存在,则返回0
- PriorElem(L,cur e,&pre e) 求前驱:若cur e是L的数据元素且不是第一个,则用pre e返回它的前驱,否则操作失败,pre e无定义
- NextElem(L,cur e,&next e)求后继 若cur e是L的数据元素,且不是最后一个,则用next e返回它的后继,否则操作失败,next e无定义。
- ListInsert(&L,i,e) 插入 在L中第i个位置之前插入新的数据元素e,L的长度加1。 1=<i<=Listlength(L)+1
- ListDelete(&L,i,&e) 删除 删除L的第i个数据元素.并用e返回其值,L的长度减1。1=<i<=Listlength(L)
- ListTraverse(L,visit0) 遍历 对给定的线性表L,依次输出L的每一个数据元素。遍历时不许重复
- Copy(L,C)复制 将给定的线性表L复制到线性表 C中。
- Merge(A.B.C)合并 将给定的线性表A和B合并为线性表C。
这些是线性表的基础操作,不用死记硬背,理解了经常用就记住了。下面我们来浅浅的应用一下:
题目
- 将所有在线性表Lb中但不在La表中的数据元素插入到La中。
算法:
void union(List&La,ListLb){
La-len=ListLength(La);
Lb-len=ListLength(Lb);
for(i=1;i<=lb-len;i++){
GetElem(Lb,i,&e);
if(!LocateElem(La,e,equal))
ListInsert(La,++La-len,e);
}
}
首先声明变量union,建议取一个简单易懂的变量名,这样第一眼就看出这个算法是干什么的。将所有在线性表Lb中但不在La表中的数据元素插入到La中,放到La中取La的地址,求出两表的长度。从第一个元素开始读取(建议从1开始,从0开始比较麻烦)Lb中数据,如果Lb与La中元素相等就PASS,不相等插入La中,La表长度加1,循环此动作直到Lb没有数据,循环结束。
线性表有两种基本存储结构:顺序存储和链式存储。
顺序存储
在线性表的顺序存储结 构中,其前后两个元素在 存储空间中是紧邻的,且前驱元素一定存储在后继元素的前面,由于线性表的所有数据元素属于同一数据类型,所以每个元素在存储器中占用的空间大小相同。
其实从名字上就可以理解,它一定是有顺序的。例如排队做核算,旁边的管理人员是不允许有人插队的(个例除外😀),每个人必须有顺序的做核酸。因此,要在顺序存储的线性表中查找某一个元素是很方便的。在程序设计过程中通常用数组来表示顺序存储的线性表(数组中的元素间的地址是连续的且数组中所有元素的数据类型是相同的,而这与线性表的顺序存储的空间结构是类似的)。
我们可以用C语言描述顺序存储结构的线性表
#define TRUE 1
#define FALSE 0
#define MAXNUM <顺序表最大元素个数>
Elemtype List MAXNUM; /*定义顺序表List*/
int num=-1; /*定义当前数据元素的下标,并初始化*/
我们还可将数组和表长封装在一个结构体中:
struct Linear_list {
Elemtype List[MAXNUM]; /*定义数组域*/
int length; /*定义表长域*/
}
对线性表进行初始化
Status InitList-Sq(Sqlist &L){
L.elem=(ElemType *) malloc (LIST-INIT- SIZE*sizeof(ElemType));
if(!L.elem) exit (OVERFLOW);
L.length=0;
L.listsize=LIST-INIT-SIZE;
Return OK;
}// InitList-Sq
求表长度
int listlength(Seqlist *L)
{
return(L->len);
}
顺序表的插入操作
int Insertlist(Squlist *L,int i, Elemtype x)
/*在顺序表*L第i个元素前插入数据元素x,若成功,返回TRUE,否则返回FALSE。*/
int j;
if (i<0|i>listlength(L))
{
printf(“Error!”); /*插入位置出错*/
return FALSE;
}
if (i>MAXNUM-1){ //顺序表List的最大数据元素个数为MAXNUM
printf(“overflow!”);
return FALSE; /*表已满*/
}
for (j=listlength(L)-1;j>=i;j--)
L->elem[j+1] = L->elem[i]; /*数据元素后移*/
L->elem[i] = x; /*插入x*/
L->length = L->length +1; /*长度加1*/
return TRUE;
}
今天的分享就到这里啦,下一篇继续写顺序存储和链式存储😃😃😃。
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。