一、定义:
线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。数据元素是一个抽象的符号,其具体含义在不同的情况下一般不同。
在稍复杂的线性表中,一个数据元素可由多个数据项(item)组成,此种情况下常把数据元素称为记录(record),含有大量记录的线性表又称文件(file)。
线性表中的个数n定义为线性表的长度,n=0时称为空表。在非空表中每个数据元素都有一个确定的位置,如用ai表示数据元素,则i称为数据元素ai在线性表中的位序。
线性表的相邻元素之间存在着序偶关系。如用(a1,…,ai-1,ai,ai+1,…,an)表示一个顺序表,则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1,2,…,n-1时,ai有且仅有一个直接后继,当i=2,3,…,n时,ai有且仅有一个直接前驱
二、线性表的抽象数据类型:
#include <studio.h>
/*
操作方法:
InitList(*L):初始化操作,建立一个空的线性表
ListEmpty(L):若线性表为空,返回True,否则返回False
ClearList(*L):将线性表清空。
GetElem(L,i,e):将线性表L中的第i个位置元素赋值给e
LocateElem(L,e):在线性表L中查找与给定值e相等的元素,如果查找成功
返回该元素在表中序号表示成功,否则,返回0表示失败
ListInsert(*L,i,e):在线性表L中的i个位置插入新元素e
ListDelete(*L,i,*e):删除线性表L中地i个位置元素,并用e返回其值
ListLength(L):返回线性表L的元素个数
*/
void union(List *La,List Lb)//union在这里只是个名字
{
int La_len,Lb_len,i;
ElemType e;/*声明一个与La和Lb相同的数据元素e*/
La_len=ListLength(La);//求线性表的长度
Lb_len=ListLength(Lb);//求线性表的长度
for(i=1;i<Lb_len;i++)//循环遍历Lb的长度
{
GetElem(Lb,i,e); //取出第i个数据元素把它赋值给e
if(!LocateElem(La,e,equal))//如果La不存在和e相同的元
ListInsert(La,++La_len,e);//就向线性表的长度里面插入新元素e
}
}
三、顺序储存方式:
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
线性表顺序存储的结构代码:
#define MAXLENGTH 20
struct sequencelist
{
int data[MAXLENGTH];
int length;
};
data数组为这个线性表的主要部分,数据元素就存在于此数组中,而对这个线性表的操作都是基于这个数组.
线性表的最大容量为:MAXLENGTH。
length是这个线性表的一个属性,表示这个线性表包含当前元素的个数。
四、地址计算方法:
储存器中的每个储存单元都有自己的编号,这个编号称为地址
假如每个数据元素的类型在储存单元中占c个储存单元,那么线性表中第i+1个数据元素的储存位置和第i个数据元素的储存位置满足下列关系(LOC表示获得储存位置的函数):
LOC(a i+1) = LOC(a i)+ c
五、六、七、顺序储存结构的插入和删除
1.线性表的取元素操作
用索引值查找元素的值。
//get list elements
//make sure elemet is NOT NULL when calling.
int getElement(struct sequencelist list,int index,int *element)
{
printf("\ngetElement\n");
int length = list.length;
printf("length is %d\n",length);
if(length ==0 || index < 0 || index >= length)
return ERROR;
*element = list.data[index];
return OK;
}
2.线性表的插入操作
(1)如果插入位置不合理,抛出异常;
(2)如果线性表长度大于等于数组长度,则抛出异常或者动态增加容量;
(3)从最后一个元素遍历到第i个位置,分别将它们后移一个位置;
(4)将要插入元素填入位置i处;
(5)表长加1;
3.线性表的删除操作
类似增的相反操作。
// Delete opration
int delete(struct sequencelist *list,int index)
{
int length = list->length;
if(length ==0 || index < 0 || index > length-1 )
return ERROR;
for(int i = index;i<length-1;i++)
{
list->data[i] = list->data[i+1];
}
list->data[length-1] = '\0';//delete the last element.
list->length--;
return OK;
}
八、九、单链表如何进行整表创建和删除?
1.整表创建:
声明一个结点p和计数器变量i;
(1)初始化一个空链表L;
(2)让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
循环:
(3)生成一新结点赋值给p;
(4)随机生成一数字赋值给p指针的数据域p->data=rand();
(5)将p结点插入到头结点与前一新结点之间。
实现代码如下:
/*随机产生n个元素的值,建立带头结点的单链表L(头插法)*/
void CreatListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0)); /*初始化随机数种子*/
*L=(LinkList)malloc(sizeof(Node));
(*L)->next=NULL; /*先建立一个带头结点的单链表*/
for(i=0;i<n;i++)
{
p=(LinkList)mallloc(sizeof(Node)); /*生成新结点*/
p->data=rand()%100+1;
p->next=(*L)->next;
(*L)->next=p; /*插入到表头*/
}
}
注:for循环中要不断使用malloc函数开辟新的空间
2.整表删除
单链表整表删除的思路如下:
(1)声明一结点p和q;
(2)将第一个结点赋值给p;
循环:
(3)将下一结点赋值给q;
释放p;
(4)将q赋值给p。
实现代码算法如下:
/*初始条件:顺序线性表L已存在,操作结果:将L重置为空表*/
Status CLearList(LinkList *L)
{
LinkList p,q;
p=(*L)->next;
while(p) /*没到表尾*/
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL; /*头结点指针域为空*/
return OK;
}
十、什么是循环列表?什么是双向链表?
由于单链表不能回到之前的结点,所以就将最后一个结点中指针域中的指针由NULL改为指向头结点的指针。
在循环链表的基础上,如果要遍历到前面的一个结点时,所需的时间复杂度为o(n),所以为了方便,在每一个结点中再新增一个指向前面一个结点的指针域。即为双向链表。