目录
1.链式存储结构定义
线性表的链式存储结构是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以存在内存中未被占用的任意位置,不需要像顺序存储结构那样只能存在指定的位置。而比起顺序存储每个数据元素只需要存储一个位置就可以了,在链式存储结构中,除了要存储数据元素信息外,还要存储它的后继元素的存储地址(指针),也就是说,除了存储其本身的信息外,还需要存储一个指示其直接后继的存储位置的信息。
2.单链表
我们把存储数据元素信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称为存储映像或称为结点(Node)。由n个结点连接成一个链表,即为线性表(a1,a2,...,an)的链式存储结构。因为此链表的每一个结点中值包含一个指针域,所以叫做单链表.对于线性表来说,都有开头和结尾,链表也不例外,我们把链表中的每一个结点的存储位置叫做头指针,最后一个结点指针为空(Null)。
3.头指针与头结点
因为头结点的数据域不存储任何信息,所以会经常被人们混淆,下面我们来说一下头结点与头指针的异同。
- 头指针
头指针是指链表指向第一个结点的指针,若链表有头指针,则是指向头结点的指针。头指针具有标识作用,我们常用头指针冠以链表的名字(即指针标量的名字)。无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
- 头结点
头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(但也可以用来存放链表的长度)。有了头结点,对在第一元素结点之前插入结点和删除第一节点等操作与对其他结点的操作就一致了。另外头结点不一定是链表的必须要素。
4.单链表存储结构
我们可以在C语言中用结构指针来描述单链表,具体代码如下:
typedef struct Node
{
ElemType data; //数据域
struct Node* Next; //指针域
}Node;
typedef struct Node* Linklist;
从上面我们可以看到结点由存放数据元素的数据域和存放后继结点地址的指针域组成。
假设p是指向线性表第i个元素的指针,则该结点ai的数据域我们可以用p->data来表示,结点ai的指针域可以用p->next来表示,p->next的值是一个指针。
5.单链表的读取
获得单链表上第i个数据的算法思路:首先声明一个结点p指向链表第一个结点,初始化j从1开始,然后当j<i时就遍历链表,让p的指针向后移动,不断指向下一个结点 j+1,若到链表末尾p为空,则说明第i个元素不存在,否则查找成功,返回结点p的数据,也就是说从头开始找,直到第i个元素或者找完链表为止。具体代码如下:
Status GetElem(LinkList,int i,ElemType *e)
{
int j;
LinkList p;
p = L->next;
j = 1;
while(p && j<i)
{
p = p->next;
++j;
}
if(!p||j>i)
{
return ERROR;
}
*e = p->data;
return OK;
}
6.单链表的插入
单链表第i个数据插入结点的算法思路:首先声明一个结点指向链表头结点,初始化j从1开始;当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;若到链表末尾p为空,则说明第i个元素不存在,否则查找成功,在系统总生成一个空结点s;然后将数据元素赋值给s->data。具体代码如下:
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p;
p = *L;
j = 1;
while(p&&j<i) //寻找第i个结点
{
p = p->next;
j++;
}
if(!p||j>i)
{
return ERROR;
}
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
7.单链表的删除
单链表第i个数据删除结点的算法思路:首先声明结点p指向链表第一个结点,初始化j=1;当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;如果到链表末尾p为空,则说明第i个元素不存在,否则查找成功,将欲删除的结点p->next赋值给q;接着单链表的删除标准语句p->next = q->next;再将q结点中的数据赋值给e,作为返回,最后释放q结点。具体代码如下:
Status ListDelete(LinkList *L,int i,Elemtype *e)
{
int j;
LinkLIst p,q;
p = *L;
j = 1;
while(p->next && j<i)
{
p = p->next;
++j;
}
if(!(p->next) || j>i)
{
return ERROR;
}
q = p->next;
p->next = q-next;
*e = q-next;
free(q);
return OK;
}