链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
#include
#include
#ifndef _LINKLIST_H
#define _LINKLIST_H
typedef int Status; //Status类型就是int型
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
typedef int ElemType; //结点的元素类型为int型
typedef struct LNode{ //单链表的结构体
ElemType data; //数据域,存储本结点的信息(数据)
struct LNode *next; //指针域,指向下一个结点的地址
}LNode, *LinkList;
//1、初始化单链表,就是创建出头结点
Status InitList_Link(LinkList &L);
//(2)判断一个链表是否是空表ListEmpty_Link
Status ListEmpty_Link(LinkList L);
//(3)求长度:ListLength_Link
int ListLength_Link_1(LinkList L); //方法一:p从L开始,即头结点
int ListLength_Link_2(LinkList L); //方法二:p从L->next开始,即第一个真正的元素结点
//(4)取第i个元素的值:GetElem_List
Status GetElem_List(LinkList L,int i,ElemType &e);
(5)向第i个位置上插入结点,值为e
Status ListInsert_Link(LinkList &L,int i,ElemType e);
//(6)删除第i个结点,注意如果i值太大或太小,删除失败,返回ERROR
Status ListDelete_Link(LinkList &L,int i,ElemType &e);
//(7)构造链表
//方法一:每次插入到最末尾,向尾生长,所得到的顺序与插入时的元素顺序一致。
Status CreateList_Link_Rear(LinkList &L,ElemType a[],int n);
//方法二:每次插入到第1个结点,就是直接插入到头结点之后,向头生长,所得到的顺序与插入时的元素顺序相反
Status CreateList_Link_Head(LinkList &L,ElemType a[],int n);
//(8)遍历链表:从表头到表尾,一个一个结点进行访问
Status TraverseList_Link(LinkList L);
//(9)查找:从链表L中查找与指定元素x相同的结点,如果存在,返回该结点指针,如果不存在,返回NULL
LinkList SearchList_Link(LinkList L,ElemType x);
//(10)清空:将链表L清空,就是将L变成一个空表
//方法一:调用前面的Delete函数,每次删除表头结点(就是删除第一个结点),这样,删除了第一个结点后,原来的第二个结点就变成了新的第一个结点,以此类推,一直删除下去,直到链表为空:
Status ClearList_Link_1(LinkList &L);
//方法二:每次都删除第1个结点,直到链表为空
Status ClearList_Link_2(LinkList &L);
//(11)销毁:销毁链表L
Status DestroyList_Link(LinkList &L);
//逆置单链表L
Status InverseList_Link(LinkList &L);
#endif
//1、初始化单链表的头结点
Status InitList_Link(LinkList &L)
{
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL; //因为L是指针,所以用->符号,也可以用:
//(*L).next=NULL;
return OK;
}
//(2)判断一个链表是否是空表ListEmpty_Link
Status ListEmpty_Link(LinkList L)
{
return L->next==NULL ? TRUE : FALSE;
}
代码如下(示例):
//(3)求长度:ListLength_Link
Status ListLength_Link_1(LinkList L) //方法一:p从L开始,即头结点
{
int n=0;
LinkList p=L;
while(p->next!=NULL)
{
n++;
p=p->next;
}
return n;
}
Status ListLength_Link_2(LinkList L) //方法二:p从L->next开始,即第一个真正的元素结点
{
int n=0;
LinkList p=L->next;
while(p!=NULL)
{
n++;
p=p->next;
}
return n;
}
Status GetElem_List(LinkList L,int i,ElemType &e)
{
LinkList p;
int n;
p=L;
n=0;
while(p->next!=NULL && n<i)
{
p=p->next;
n++;
}
if(n<i)
return ERROR;
e=p->data; //获取的值
return OK;
}
Status ListInsert_Link(LinkList &L,int i,ElemType e)
{ //向链表L的第i个位置插入元素e
LinkList p;
int n;
p=L;
n=0;
while(p!=NULL && n<i-1) //寻找p,让p指向第i-1个元素
{
p=p->next;
n++;
}
if(p==NULL || n>=i) //i的值太大或太小,插入位置非法
return ERROR;
LinkList s;
s=(LinkList)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
//(6)删除第i个结点,注意如果i值太大或太小,删除失败,返回ERROR
Status ListDelete_Link(LinkList &L,int i,ElemType &e)
{
//先找到第i-1个结点,由p指向它
LinkList p,s;
int n;
p=L;
n=0;
while(p!=NULL && n<i-1) //寻找p,让p指向第i-1个元素
{
p=p->next;
n++;
}
if(p->next==NULL || n>i-1) //如果i的值太大或太小,无法删除
return ERROR;
s=p->next;
p->next=s->next;
e=s->data;
free(s);
return OK;
}
//方法一:每次插入到最末尾,向尾生长,所得到的顺序与插入时的元素顺序一致。
Status CreateList_Link_Rear(LinkList &L,ElemType a[],int n)
{ //向尾生长方式,将有n个元素的数组a中的元素生成链表L
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
LinkList p=L; //让p始终指向表尾,方便插入操作
LinkList s;
int i;
for(i=0;i<n;i++)
{
s=(LinkList)malloc(sizeof(LNode));
s->data=a[i];
s->next=NULL;
p->next=s;
p=s;
}
return OK;
}
//方法二:每次插入到第1个结点,就是直接插入到头结点之后,向头生长,所得到的顺序与插入时的元素顺序相反
Status CreateList_Link_Head(LinkList &L,ElemType a[],int n)
{ //向头生长方式,将有n个元素的数组a中的元素生成链表L
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
LinkList s;
int i;
for(i=0;i<n;i++)
{
s=(LinkList)malloc(sizeof(LNode)); //生成新结点
s->data=a[i];
s->next=L->next; //s作为第一个结点,就是直接插入到头结点的后面
L->next=s;
}
return OK;
}
//(8)遍历链表:从表头到表尾,一个一个结点进行访问
Status TraverseList_Link(LinkList L)
{
LinkList p=L->next;
while(p!=NULL)
{
printf("%5d",p->data); //输出p的值
p=p->next;
}
putchar('\n');
return OK;
}
//(9)查找:从链表L中查找与指定元素x相同的结点,如果存在,返回该结点指针,如果不存在,返回NULL
LinkList SearchList_Link(LinkList L,ElemType x)
{
LinkList p=L->next;
while(p!=NULL)
{
if(p->data==x)
break;
p=p->next;
}
return p;
}
//方法一:调用前面的Delete函数,每次删除表头结点(就是删除第一个结点),这样,删除了第一个结点后,原来的第二个结点就变成了新的第一个结点,以此类推,一直删除下去,直到链表为空:
Status ClearList_Link_1(LinkList &L)
{
ElemType e;
while(!ListEmpty_Link(L)) //一直删除,直到链表为空
ListDelete_Link(L,1,e); //删除第一个结点
return OK;
}
//方法二:每次都删除第1个结点,直到链表为空
Status ClearList_Link_2(LinkList &L)
{
LinkList p=L->next; //p始终指向第一个结点,就是L后面的
while(p!=NULL)
{
L->next=p->next; //L->next绕过p,指向p后面的那个结点
free(p); //删除p
p=L->next; //p始终指向第一个结点,就是L后面的
}
return OK;
}
Status DestroyList_Link(LinkList &L)
{
ClearList_Link_1(L); //先将链表清空
free(L); //然后再将头结点释放
L=NULL; //释放了的指针,通常应该让它指向NULL
return OK;
}
Status InverseList_Link(LinkList &L)
{
LinkList M;
M=(LinkList)malloc(sizeof(LNode)); //先生成一个头结点M
M->next=NULL;
LinkList p=L->next;
while(p!=NULL)
{
L->next=p->next; //先让p从L中脱落,就是让L绕过p
p->next=M->next; //将p结点向头生长插入到M的第一个结点
M->next=p;
p=L->next; //p又指向L中的第一个结点
}
free(L);
L=M;
return OK;
}
#include "LinkList.h"
#include
#include
//1、初始化单链表的头结点
Status InitList_Link(LinkList &L)
{
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL; //因为L是指针,所以用->符号,也可以用:
//(*L).next=NULL;
return OK;
}
//(2)判断一个链表是否是空表ListEmpty_Link
Status ListEmpty_Link(LinkList L)
{
return L->next==NULL ? TRUE : FALSE;
// return !(L->next);
// if(L->next==NULL)
// return TRUE;
// else
// return FALSE;
}
//(3)求长度:ListLength_Link
Status ListLength_Link_1(LinkList L) //方法一:p从L开始,即头结点
{
int n=0;
LinkList p=L;
while(p->next!=NULL)
{
n++;
p=p->next;
}
return n;
}
Status ListLength_Link_2(LinkList L) //方法二:p从L->next开始,即第一个真正的元素结点
{
int n=0;
LinkList p=L->next;
while(p!=NULL)
{
n++;
p=p->next;
}
return n;
}
//(4)取第i个元素的值:GetElem_List
Status GetElem_List(LinkList L,int i,ElemType &e)
{
LinkList p;
int n;
p=L;
n=0;
while(p->next!=NULL && n<i)
{
p=p->next;
n++;
}
if(n<i)
return ERROR;
e=p->data;
return OK;
}
//(5)向第i个位置上插入结点,值为e
Status ListInsert_Link(LinkList &L,int i,ElemType e)
{ //向链表L的第i个位置插入元素e
LinkList p;
int n;
p=L;
n=0;
while(p!=NULL && n<i-1) //寻找p,让p指向第i-1个元素
{
p=p->next;
n++;
}
if(p==NULL || n>=i) //i的值太大或太小,插入位置非法
return ERROR;
LinkList s;
s=(LinkList)malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
//(6)删除第i个结点,注意如果i值太大或太小,删除失败,返回ERROR
Status ListDelete_Link(LinkList &L,int i,ElemType &e)
{
//先找到第i-1个结点,由p指向它
LinkList p,s;
int n;
p=L;
n=0;
while(p!=NULL && n<i-1) //寻找p,让p指向第i-1个元素
{
p=p->next;
n++;
}
if(p->next==NULL || n>i-1) //如果i的值太大或太小,无法删除
return ERROR;
s=p->next;
p->next=s->next;
e=s->data;
free(s);
return OK;
}
//(7)构造链表
//方法一:每次插入到最末尾,向尾生长,所得到的顺序与插入时的元素顺序一致。
Status CreateList_Link_Rear(LinkList &L,ElemType a[],int n)
{ //向尾生长方式,将有n个元素的数组a中的元素生成链表L
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
LinkList p=L; //让p始终指向表尾,方便插入操作
LinkList s;
int i;
for(i=0;i<n;i++)
{
s=(LinkList)malloc(sizeof(LNode));
s->data=a[i];
s->next=NULL;
p->next=s;
p=s;
}
return OK;
}
//方法二:每次插入到第1个结点,就是直接插入到头结点之后,向头生长,所得到的顺序与插入时的元素顺序相反
Status CreateList_Link_Head(LinkList &L,ElemType a[],int n)
{ //向头生长方式,将有n个元素的数组a中的元素生成链表L
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
LinkList s;
int i;
for(i=0;i<n;i++)
{
s=(LinkList)malloc(sizeof(LNode)); //生成新结点
s->data=a[i];
s->next=L->next; //s作为第一个结点,就是直接插入到头结点的后面
L->next=s;
}
return OK;
}
//(8)遍历链表:从表头到表尾,一个一个结点进行访问
Status TraverseList_Link(LinkList L)
{
LinkList p=L->next;
while(p!=NULL)
{
printf("%5d",p->data); //输出p的值
p=p->next;
}
putchar('\n');
return OK;
}
//(9)查找:从链表L中查找与指定元素x相同的结点,如果存在,返回该结点指针,如果不存在,返回NULL
LinkList SearchList_Link(LinkList L,ElemType x)
{
LinkList p=L->next;
while(p!=NULL)
{
if(p->data==x)
break;
p=p->next;
}
return p;
}
//(10)清空:将链表L清空,就是将L变成一个空表
//方法一:调用前面的Delete函数,每次删除表头结点(就是删除第一个结点),这样,删除了第一个结点后,原来的第二个结点就变成了新的第一个结点,以此类推,一直删除下去,直到链表为空:
Status ClearList_Link_1(LinkList &L)
{
ElemType e;
while(!ListEmpty_Link(L)) //一直删除,直到链表为空
ListDelete_Link(L,1,e); //删除第一个结点
return OK;
}
//方法二:每次都删除第1个结点,直到链表为空
Status ClearList_Link_2(LinkList &L)
{
LinkList p=L->next; //p始终指向第一个结点,就是L后面的
while(p!=NULL)
{
L->next=p->next; //L->next绕过p,指向p后面的那个结点
free(p); //删除p
p=L->next; //p始终指向第一个结点,就是L后面的
}
return OK;
}
//(11)销毁:销毁链表L
Status DestroyList_Link(LinkList &L)
{
ClearList_Link_1(L); //先将链表清空
free(L); //然后再将头结点释放
L=NULL; //释放了的指针,通常应该让它指向NULL
return OK;
}
//逆置单链表L
Status InverseList_Link(LinkList &L)
{
LinkList M;
M=(LinkList)malloc(sizeof(LNode)); //先生成一个头结点M
M->next=NULL;
LinkList p=L->next;
while(p!=NULL)
{
L->next=p->next; //先让p从L中脱落,就是让L绕过p
p->next=M->next; //将p结点向头生长插入到M的第一个结点
M->next=p;
p=L->next; //p又指向L中的第一个结点
}
free(L);
L=M;
return OK;
}