# 链表
### 链表是什么呢?
链表和数组一样同属于线性表,即一种线性存储结构,它可分为两种,即顺序存储结构和链式存储结构,前者其特点是逻辑关系上相邻的两个元素在物理上也相邻,而链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构
**特点:**
用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的
可分为单链表,双向链表,循环链表,静态链表
### <u>**操作(只讲单链表):**</u>
**//单链表的存储结构**
```c
typedef struct LNode
{
ElemType data//结点的数据域
struct LNode *next;//结点的指针域(LNode *定义指向单链表中任意结点的指针变量)
}LNode,*LinkList;//LinkList为指向结构体LNode的指针类型
```
这里定义的是单链表中每个结点的存储结构,它包括两部分:存储结点的数据域data,其类型通用类型标识符ElemType表示;存储后继结点位置的指针域next,其类型为指向结点的指针类型LNode*
对于我来说,首元结点,头结点,头指针容易弄混,加以说明:
1.首元结点是指链表中存储第一个数据元素的结点
2.头结点是在首元结点之前附设的一个结点,其指针域指向首元结点。头结点的数据域可以不存储任何信息,也可存储与数据元素类型相同的其他附加信息
3.头指针是指向链表中第一个结点的指针。若链表设有头结点,则头结点所指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线性表的首元结点
**//初始化**
```c
Status InitList(LinkList &L)
{
head=(LNode*)malloc(sizeof(LNode));//生成新结点作为头结点,用头指针L指向头结点
L->next=NULL;//头结点的指针域置空
return OK;
}
```
**//取值**
```c
(根据序号i获取元素的值,用e返回L中第i个数据元素的值
Status GetElem(LinkList &L,int i,ElemType &e)
{
p=L->next,j=1;//初始化,p指向首元结点,计数器j初值赋为1
while(p!=NULL&&j<i)//顺链域向后查找,直到p为空或p指向第i个元素
{
p=p->next;//p指向下一个结点
j++;//计数器相应加一
}
if(p==NULL||j>i)//i值不合法
return ERROR;
e=p->data;//取第i个结点的数据域
return OK;
}
```
**//查找**
```c
(在单链表中查找值为e的元素)
LNode *LocateElem(LinkList L,ElemType e)
{
p=L->next;//初始化,p指向首元结点
while(p!=NULL&&p->data!=e){//顺链域向后查找,直到p为空域或p所指结点的数据域为e
p=p->next;//p指向下一个结点
}
return p;//查找成功返回值为e的结点地址p,查找失败p为NULL
}
```
**//插入**
```c
(将值为e的新结点插入表的第i个结点的位置)
Status ListInsert(LinkList &L,int i,ElemType e)
{
p=L,j=0;
while(p!=NULL&&j<i-1)
{
p=p->next;//查找第i-1个元素,p指向该结点
j++;
}
if(p==NULL||j>i-1)
return ERROR;
s=(LNode*)malloc(sizeof(LNode));//生成新结点*s
s->data=e;//将结点*s的数据域置为e
s->next=p->next;//将结点*s的指针域指向结点ai
p->next=s;//将结点*p的指针域指向结点*s
return OK;
}
```
和顺序表一样,如果表中有n个结点,则插入操作中合法的插入位置有n+1个,即1<=i<=n+1。当i=n+1时,新结点则插在链表尾部
**//删除**
```c
(在带头结点的单链表L中,删除第i个元素)
Status deletelist(LinkList &L,int i)
{
p=L,j=0;
while((p->next!=NULL)&&(j<i-1))//查找第i-1个结点,p指向该结点
{
p=p->next;
j++;
}
if((p->next==NULL)||(j>i-1))
return ERROR;
q=p->next;//临时保存被删结点的地址以备释放
p->next=q->next;//改变删除结点前驱结点的指针域
delete(q);//释放删除结点的空间
return OK;
}
```
**//创建单链表(前插法和后插法)**
```c
/头插法(逆位序输入n个元素的值,建立带表头结点的单链表L)
void creatlist(LinkList &L,int n)
{
L=(LNode*)malloc(sizeof(LNode));
L->next=NULL;
for(i=0;i<n;i++){
p=(LNode*)malloc(sizeof(LNode));
scanf("%d",p->data);
p->next=L->next;
L->next=p;
}
}//后插法(正位序输入n个元素的值,建立带表头结点的单链表L)
void creatlist(LinkList &L,int i)
{
L=(LNode*)malloc(sizeof(LNode));//生成新结点
L->next=NULL;
r=L;//尾指针指向头结点
for(i=0;i<n;i++){
p=(LNode*)malloc(sizeof(LNode));//生成新结点
scanf("%d",&p->data);//输入元素值赋给新结点*p的指针域
p->next=NULL;
r->next=p;//将新结点*p插入尾结点*r之后
r=p;//r指向新的尾结点*p
}
}
```