线性表和线性链表


线性表的定义

线性表(list):零个或多个数据元素的有限序列

顺序存储定义
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素

顺序存储方式
一维数组来实现顺序存储结构

#define MAXSIZE 20		/*存储空间初始分配量*/
typedef int ElemType;		/*ElemType类型根据实际情况而定,这里假设为int*/
typedef struct
{
ElemType data[MAXSIZE];	/*数组存储数据元素,最大值为MAXSIZE*/
int length;				/*线性表当前长度*/
}SqList;

顺序存储结构需要三个属性
1.存储空间的起始位置:数组data,它的存储位置就是存储空间的存储位置
2.线性表的最大存储空间:数组长度MaxSize
3.线性表的当前长度length
存储器中每个存储单元都有自己的编号,这个编号叫做地址

获得元素操作

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
/*Status是函数的类型,其值是函数结果状态代码,如OK等*/
/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值*/
```c
Status GetElem(SqList L,int i, ElemType *e)
{
if(L.length == 0 || i < 1 || i>L.length)
return ERROR;
*e = L.data[i - 1];
return OK;
}

插入操作

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L),*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert(SqList *L,int i, ElemType e)
{
int k;
if(L->length==MAXSIZE)		/*顺序线性表已经满
return ERROR;
if(i<1 || i>L->length + 1)		/*当i不再范围内时*/
return ERROR;
if(i<= L->length)			/*若插入数据位置不在表尾*/
{
for(k=L->length-1;k>=i-1;k--)	/*将要插入位置后数据元素向后移动一位*/
L->data[k+1] = L->data[k];
}
L->data[i-1]=e;				/*将新元素插入*/
L->length++;
return OK;
}

删除操作

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(SqList *L, int i, ElemType *e)
{
int k;
if(L->length==0)		/*线性表为空*/
return ERROR;
if( i < 1 || i > L->length)	/*删除位置不正确*/
return ERROR;
*e = L->data[i-1];
if(i<L->length)
{
for(k=i;k<L->length;k++)	/*将删除位置后继元素前移*/
L->data[k-1]=L->data[k];
}
L->length--;
return OK;
}

线性表顺序存储结构的优缺点
优点
1.无须为表示表中元素之间的逻辑关系而增加额外的存储空间
2.可以快速地存取表中任一位置的元素

缺点
1.插入和删除操作需要移动大量元素
2.当线性表长度变化较大时,难以确定存储空间的容量
3.造成存储空间的“碎片”

线性表链式存储结构定义

为了表示每个数据元素ai与其直接后继数据元素a(i+1)之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或域。这两部分信息组成数据ai的存储映像,称为结点(Node)。

n个结点(ai的存储映像)链接成一个链表,即为线性表(a1,a2,```,an)的链接存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。
我们把链表中第一个结点的存储位置叫做头指针。有时,我们为了更加方便地对链表进行操作,会在单链表的第一个结点前附设一个结点,称为头结点。

单链表

/*线性表的单链表存储结构*/
typedef struct Node
{
Elemtype data;
struct Node *next;
}Node;
typedef struct Node *LinkList;			/*定义LinkList*/

结点由存放数据元素的数据域存放后继结点地址的指针域组成。
单链表的读取

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值*/
Status GetElem(LinkList L,int i, ElemType *e)
{
int j;
LinkList p;		/*声明一结点p*/
p = L->next;		/*让p指向链表L的第一个结点*/
j = 1;			/*j为计数器*/
while(p && j<i)		/*p不为空或者计数器j还没有等于i时,循环继续*/
{
p = p->next;		/*让p指向下一个结点*/
++j;
}
if(!p || j > i)
return ERROR;	/*第i个元素不存在*/
*e = p->data;		/*取第i元素的数据*/
return OK;
}

单链表的插入

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while(p && j < i)		/*寻找第i个结点*/
{
p=p->next;
++j;
}
if(!p || j > i)
return ERROR;		/*第i个元素不存在*/
s = (LinkList)malloc(sizeof(Node));		/*生成新结点*/
s->data = e;
s->next = p->next;					/*将p的后继结点赋值给s的后继*/
p->next = s;						/*将s赋值给p的后继*/
return OK;
}

单链表的删除

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(LinkList *L, int i, ElemType *e)
{
int j;
LinkList p,q;
p = *L;
j = 1;
while(p->next && j < i)	/*遍历查找第i个元素*/
{
p = p->next;
j++;
}
if(!(p->next) || j > i)
return ERROR;		/*第i个元素不存在*/
q = p->next;
p->next = q->next;			/*将q的后继赋值给p的后继*/
*e = q->data;				/*将q结点中的数据给e*/
free(q);					/*让系统回收此结点,释放内存*/
return OK;
}

单链表的整表创建

/*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)*/
void CreateListHead(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)malloc(sizeof(Node);	/*生成新结点*/
p->data = rand()%100 + 1;		/*随机生成100以内的数字*/
p->next = (*L)->next;
(*L)->next = p;					/*插入到表头*/
}
}
/*随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法)*/
void CreateListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time (0));			/*初始化随机数种子*/
*L = (LinkList)malloc(sizeof(Node));/*为整个链表*/
r = *L;					/*r为指向尾部的结点*/
for(i = 0; i<n;i++)
{
p = (LinkList)malloc(sizeof(Node);	/*生成新结点*/
p->data = rand()%100 + 1;		/*随机生成100以内的数字*/
r->next = p;					/*将表尾终端结点的指针指向新结点*/
r= p;							/*将当前的新结点定义为表尾终端结点*/
}
r->next = NULL;			/*表示当前链表结束*/
}

单链表的整表删除

/*初始条件:顺序线性表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;
}

静态链表

/*线性表的静态链表存储结构*/
#define MAXSIZE 1000		/*假设链表的最大长度是1000*/
typedef struct
{
ElemType data;
int cur;					/*游标(Cursor),为0时表示无指向
}Component,StaticLinkList[MAXSIZE];
/*将一维数组space中各分量链成一备用链表*/
/*space[0],cur为头指针,“0”表示空指针*/
Status InitList(StaticLinkList space)
{
int i;
for(i=0;i < MAXSIZE-1;i++)
space[i].cur = i+1;
space[MAXSIZE-1].cur = 0;	/*目前静态链表为空,最后一个元素的cur为0*/
return OK;
}

静态链表的插入操作

/若备用空间链表非空,则返回分配的结点下标,否则返回0*/
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur;			/*当前数组第一个元素的cur存的值*/
/*就是要返回的第一个备用空间的下标*/
if(space[0].cur)
space[0].cur = space[i].cur;	/*由于要拿出一个分量来使用了,所以我们*/
/*就得把它的下一个分量用来做备用*/
return i;
}
/*在L中第i个元素之前插入新得数据元素e*/
Status ListInsert(StaticLinkList L,int i,ElemType e)
{
int j, k, l;
k = MAX_SIZE -1;			/*注意k首先是最后一个元素的下标*/
if(i<1||i>ListLength(L)+1
return ERROR;
j = Malloc_SSL(L);			/*获得空闲分量的下标*/
if(j)
{
L[j].data = e;			/*将数据赋值给此分量的data*/
for(l = 1;l <= i -1;l++)	/*找到第i个元素之前的位置*/
k = L[k].cur;
L[j].cur = L[k].cur;		/*把第i个元素之前的cur赋值给新元素的cur*/
L[k].cur = j;			/*把新元素的下标赋值给第i个元素之前的cur*/
return OK;
}
return ERROR;
}

静态链表的删除操作

/*删除在L中第i个数据元素*/
Status ListDelete(StaticLinkList L,int i)
{
int j, k;
if(i < 1 ||i > ListLength(L)
return ERROR;
k = MAX_SIZE-1;
for(j = 1;j <= i -1;j++)
k = L[k].cur;
j = L[k].cur;
L[k].cur = L[j].cur;
Free_SSL(L,j);
return OK;
}
/*将下标为k的空闲结点回收到备用链表中*/
void Free_SSL(StaticLinkList space,int k)
{
space[k].cur = space[0].cur;	/*把第一个元素cur值赋给要删除的分量cur*/
space[0].cur = k;			/*把要删除的分量下标赋值给第一个元素的cur*/
}
/*初始条件:静态链表L已存在。操作结果:返回L中数据元素个数*/
int ListLength(StaticLinkList L)
{
int j = 0;
int i = L[MAXSIZE-1].cur;
while(i)
{
i = L[i].cur;
j++;
}
return j;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值