通常情况下,链接可分为单链表、双向链表和循环链表三种常用类型。
一、单链表基本操作的实现
使用链式存储结构来实现的线性表称为链表。首元结点、头结点、头指针、空指针。
1.单链表的类型定义
typedef struct LNode//结点类型
{
LElemType data;//数据域
struct LNode * next;//指针域
} LNode, * LinkList;
2.初始化操作InitLinkList(&L)
Status InitLinkList(LinkList &L)
{//创建空的带头结点的单链表L
L=(LinkList)malloc(sizeof(LNode));//申请头结点
if(!F) return OVERFLOW;//若失败
L->next=NULL;//头结点的后继指针域赋为NULL
returnOK;
}
3.求表长操作listLength(&L)
intlistLength(LinkList L)
{
LNode*p=L;//p指向头结点
int j=0;while(p->next)//当存在
{
p=p->next;//指针后移,指向后继
j++;
}return j;//返回计数器
}
4.取元素操作getElem(LinkList L,int i,LElemType &e)
Status getElem(LinkList L,int i,LElemType &e)
{
LNode*p=L;int j=0;while(jnext)//不为i结点,且不为最后一个
{
p=p->next;//向后查找
j++;
}if(j==i)//若找到
{
e=p->data;//由e返回其值
returnOK;
}else return ERROR;//若没找到,返回ERROR
}
5.按值查找locateElem(L,e)
LinkList locateElem(LinkList L,LElemType e)
{
LNode*p=L->next;//p指向第一个结点
while(p&&!equal(p->data,e))//若不等于e
p=p->next;//向后查找
if(p) return p;//找到
else return NULL;//没找到
}
6.插入操作listInsert(&L,i,e)
Status listInsert(LinkList &L,inti,LElemType e)
{//在单链表L的第i个位置插入一个值为e的结点
LNode *p=L,*q;//q用于指向想要插入的结点
int j=0;while(jnext)
{
p=p->next;
j++;
}if(j==i-1)//在j后插入新结点
{
q=(LNode *)malloc(sizeof(LNode));//生成新结点
if(!q) returnOVERFLOW;
q->data=e;
q->next=p->next;
p->next=q;returnOK;
}else returnERROR;
}
7.删除操作listDelete(&L,i,&e)
Status listDelete(LinkList &L,int i,LElemType &e)
{
LNode*p=L,*q;int j=0;while(jnext)
{
p=p->next;
j++;
}if(j==i-1&&p->next)//判断i结点是否存在
{
q=p->next;
p->next=q->next;
e=q->data;//由e返回删除元素的值
free(q);
}else returnERROR;
}
8.头插法建立单链表操作createList(&L,n)
void createList(LinkList &L,intn)
{//依次读入n个元素,建立单链表L
LNode *p;inti;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;for(i=1;i<=n;i++)
{
p=(LNode *)malloc(sizeof(LNode));//生成p结点
inputListElem(p->data);//调用元素读入函数
p->next=L->next;
L->next=P;
}
}
9.尾插法建立单链表操作createList(&L,n)
void createList(LinkList &L,intn)
{//依次读入n个元素,建立单链表L
LNode *p,*r;inti;
L=(LinkList)malloc(sizeof(LNode));//生成头结点
r=L;//尾指针r指向头结点
for(i=1;i<=n;i++)
{
p=(LNode *)malloc(sizeof(LNode));//生成p结点
inputListElem(p->data);//调用元素读入函数,读入p结点的值
r->next=p;//把p结点放到r结点后,尾
r=p; //重置r
}
r->next=NULL; //最后一个结点后继指针为空
}
二、双向链表基本操作的实现
1.双向链表的类型定义
typedef structDLNode
{
LElemType data;struct DLNode *prior;struct DLNode *next;
}DLNode,* DLinkList;
2.插入操作算法
Status listInsert(DLinkList &L,inti,LElemType e)
{
DLNode*p=L,*q;int j=0;while(p->next&&j
{
p=p->next;
j++;
}if(j==i-1)
{
q=(DLNode *)malloc(sizeof(DLNode));if(!q) returnOVERFLOW;
q->data=e;
q->next=p->next;
q->prior=p;if(p->next) p->next->prior=q;
p->next=q;returnOK;
}else returnFALSE;
}
3.删除操作算法
Status listDelete(DLinkList &L,int i,LElemType &e)
{
DLNode*p=L;int j=0;while(p->next&&j
{
p=p->next;
j++;
}if(j==i)
{
e=p->data;
p->prior->next=p->next;if(p->next) p->next->prior=p->prior;free(p);returnOK;
}else returnFLASE;
}
三、循环链表的认识和使用
首尾相接的链表就是循环链表,单链表和双链表均可以构成循环链表。
1.循环链表 表尾结点的判定p->next=L;2.循环单链表合并算法
void unionCirList(LinkList &R1,LinkList &R2)
{
LNode*q=R2->next;
R2->next=R1->next;
R1->next=q->next;free(q);
}
四、链表实例——约瑟夫环问题
1.问题描述:
设编号为1、2、3...、n的n个人围坐一圈,约定从编号为k(1=
2.算法描述:
1 #include
2 #include
3 typedef structpersonNode4 {5 int num;//人员编号
6 struct personNode *next;7 }personNode,*personList;8 //由n个人组成的约瑟夫环问题,从第k个人开始,数到m就出列
9 void Josephus(int n,int m,intk)10 {11 inti,j;12 personList r,p;13 r=NULL;//尾指针
14 if(n>0)//创建第一个结点
15 {16 r=(personList)malloc(sizeof(personNode));17 r->num=1;18 r->next=r;19 }20 for(i=2;i<=n;i++)21 {22 p=(personList)malloc(sizeof(personNode));23 p->num=i;24 p->next=r->next;25 r->next=p;//在r结点后插入p结点
26 r=p;//重置r
27 }28 p=r->next;//p指向第1个人员结点
29 for(i=1;inext;//p指向第k个结点
33 }34 for(i=1;inext;//p指向出列结点
40 }41 printf("%d",p->num);//输出人员编号
42 r->next=p->next;43 free(p);//删除已出列的结点
44 p=r->next;//下一计数为1的结点
45 }46 printf("%d\n",r->num);//输出最后出列人员编号
47 free(r);//删除最后一个结点
48 }49
50 intmain()51 {52 intn,m,k;53 printf("**********约瑟夫环问题************\n");54 printf("输入n,m,k:");55 scanf("%d,%d,%d",&n,&m,&k);56 printf("出列的人员顺序为:");57 Josephus(n,m,k);58 system("pause");59 return 0;60 }
输出结果: