通常情况下,链接可分为单链表、双向链表和循环链表三种常用类型。
一、单链表基本操作的实现
使用链式存储结构来实现的线性表称为链表。首元结点、头结点、头指针、空指针。
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 return OK; }
3.求表长操作listLength(&L)
int listLength(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(j<i&&p->next)//不为i结点,且不为最后一个 { p=p->next;//向后查找 j++; } if(j==i)//若找到 { e=p->data;//由e返回其值 return OK; } 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,int i,LElemType e) { //在单链表L的第i个位置插入一个值为e的结点 LNode *p=L,*q;//q用于指向想要插入的结点 int j=0; while(j<i-1&&p->next) { p=p->next; j++; } if(j==i-1)//在j后插入新结点 { q=(LNode *)malloc(sizeof(LNode));//生成新结点 if(!q) return OVERFLOW; q->data=e; q->next=p->next; p->next=q; return OK; } else return ERROR; }
7.删除操作listDelete(&L,i,&e)
Status listDelete(LinkList &L,int i,LElemType &e) { LNode *p=L,*q; int j=0; while(j<i-1&&p->next) { 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 return ERROR; }
8.头插法建立单链表操作createList(&L,n)
void createList(LinkList &L,int n) { //依次读入n个元素,建立单链表L LNode *p; int i; 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,int n) { //依次读入n个元素,建立单链表L LNode *p,*r; int i; 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 struct DLNode { LElemType data; struct DLNode * prior; struct DLNode * next; }DLNode,* DLinkList;
2.插入操作算法
Status listInsert(DLinkList &L,int i,LElemType e) { DLNode *p=L,*q; int j=0; while(p->next&&j<i-1) { p=p->next; j++; } if(j==i-1) { q=(DLNode *)malloc(sizeof(DLNode)); if(!q) return OVERFLOW; q->data=e; q->next=p->next; q->prior=p; if(p->next) p->next->prior=q; p->next=q; return OK; } else return FALSE; }
3.删除操作算法
Status listDelete(DLinkList &L,int i,LElemType &e) { DLNode *p=L; int j=0; while(p->next&&j<i) { 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); return OK; } else return FLASE; }
三、循环链表的认识和使用
首尾相接的链表就是循环链表,单链表和双链表均可以构成循环链表。
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=<k=<n)的人开始从1报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的人出列,以此类推,直到所有人都出列为止,由此产生一个编号序列。
2.算法描述:
1 #include <stdio.h> 2 #include <stdlib.h> 3 typedef struct personNode 4 { 5 int num;//人员编号 6 struct personNode * next; 7 }personNode,* personList; 8 //由n个人组成的约瑟夫环问题,从第k个人开始,数到m就出列 9 void Josephus(int n,int m,int k) 10 { 11 int i,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;i<k;i++) 30 { 31 r=p; 32 p=p->next;//p指向第k个结点 33 } 34 for(i=1;i<n;i++) 35 { 36 for(j=1;j<m;j++) 37 { 38 r=p; 39 p=p->next;//p指向出列结点 40 } 41 printf("%d",p->num);//输出人员编号 42 r->next=p->next; 43 free(p);//删除已出列的结点 44 p=r->next;//下一计数为1的结点 45 } 46 printf("%d ",r->num);//输出最后出列人员编号 47 free(r);//删除最后一个结点 48 } 49 50 int main() 51 { 52 int n,m,k; 53 printf("**********约瑟夫环问题************ "); 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 }
输出结果: