单链表概述
线性表的顺序表的优点是随机存取表中的任意元素,但是它的缺点也是明显的,那就是在进行基本操作中的向顺序表中插入和删除数据元素时需要移动大量的元素。因此产生线性表的另一种链式存储结构,也就是单链表。它没有顺序表的弱点,但是也失去了顺序表的优点。
线性表的链式存储结构的特点是用一组任意的存储单元线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的村相互位置)。这两部分信息组成数据元素ai的存储映像,称为结点。它包括两个域:其中存储数据元素信息的域称为数据域,存储直接后继存储位置的域称为指针域。指针域存储的信息称为指针或链。n个结点的链结成一个链表,即为线性表的链式存储结构。又由于此链表的每个结点中只包含一个指针域,故又称为线性链表或单链表。
下面示例
线性表(zhao,qian,sun, li, zhou,wu,zheng,wang)
线性链表
头指针 H 31
存储地址 数据域 指针域
1 li 43
7 qian 13
13 sun 1
19 wang NULL
25 wu 37
31 zhao 7
37 zheng 19
43 zhou 2
整个链表的存取必须从头指针开始进行,头指针指示链表中的第一个结点(即第一个数据元素的存储映像)的存储位置。同时由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为“NULL”。
用线性链表表示线性表时,数据元素之间的逻辑关系是由结点中的指针指示的。换句话说,指针为数据元素之间的逻辑关系的映像,则逻辑上相邻的两个数据元素其存储的物理位置不要求紧邻,这种存储结构为非顺序存储映像或链式映像。
通常我们把链表画成用箭头相连接的结点的序列,结点之间的箭头表示链域中的指针。因此上述的示例的线性链表的逻辑状态为:
单链表的存储结构为:
<span style="font-size:18px;">typedef struct LNode//重新定义结构类型为LNode
{
ElemType date;//定义的结点的数据域
struct LNode *next;//定义的结点的指针域
}LNode,*LinkLIst//定义的LNode类型的变量LinkList
</span>
有时我们在单链表中的第一个头结点之前附设一个结点,称为头结点。因此带头结点的单链表表示为:
单链表进行插入和删除的图片为:
单链表的基本操作:
0基本操作前的准备
<span style="font-size:18px;">#include <iostream>
using namespace std;
#include <malloc.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int ElemType;
typedef int Status;
typedef struct LNode//重新定义结构类型为LNode
{
ElemType data;//定义的结点的数据域
struct LNode *next;//定义的结点的指针域
}LNode,*LinkList;//定义的LNode类型的变量LinkList</span>
1初始化链表
<span style="font-size:18px;">//1初始化链表
Status InitList(LinkList &L)
{
L=(LinkList)malloc(sizeof(LNode));
if(!L)
{
return(OVERFLOW);
}
L->next=NULL;
return OK;
}</span>
2销毁链表
<span style="font-size:18px;">//2销毁链表
Status DestoryList(LinkList &L)
{
LinkList q;
while(L)
{
q=L->next;
free(L);
L=q;
}
return OK;
}</span>
3清空链表
<span style="font-size:18px;">//3清空链表
Status CLearList(LinkList &L)
{
LinkList p,q;
p=L->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;
return OK;
}</span>
4判断链表是否为空
<span style="font-size:18px;">//4判断链表是否为空
Status ListEmpty(LinkList L)
{
if (L->next)
{
return FALSE;
}
else
{
return TRUE;
}
}</span>
5返回链表的长度
<span style="font-size:18px;">Status ListLength (LinkList L)
{
int i=0;
LinkList p;
p=L->next;
while(p)
{
i++;
p=p->next;
}
return i;
}</span>
6返回线性表第i个数据元素的值
<span style="font-size:18px;">//6返回线性表第i个数据元素的值
Status GetElem_L(LinkList L,int i,ElemType &e)//L为带头结点的单链表的头指针
{
LinkList p=L->next;
int j=1;//初始化,p指向第一个结点,j为指示器
while (p&&j<i)//顺时针向后查找,直到p指向第i个元素或p为空
{
p=p->next;
++j;
}
if(!p||j>i)
{
return ERROR;//第i个元素不存在
}
e=p->data; //取第i个元素
return OK;
}</span>
7向链表插入数据元素
<span style="font-size:18px;">//7向链表插入数据元素
Status ListInsert(LinkList &L,int i,ElemType e)
{
LinkList p=L;
int j=0;
while(p&&j<i-1)
{
p=p->next;
++j;
}
if(!p||j>i-1)
{
return ERROR;
}
LinkList s=(LinkList)malloc(sizeof(LNode)); //生成新结点
s->data=e;
s->next=p->next; //插入L中
p->next=s;
return OK;
}</span>
8删除链表中的元素
<span style="font-size:18px;">//8删除链表中的元素
Status ListDelete_L(LinkList &L,int i,ElemType &e)
{
LinkList p=L;
int j=0;
while(p->next&&j<i-1)
{
p=p->next;
++j;
}
if (!(p->next)||j>i-1)
{
return ERROR;
}//删除位置不合理
LinkList q=p->next;
p->next=q->next;//删除并释放结点
e=q->data;
free(q);
return OK;
}</span>