数据结构(二)线性表——链表

通常情况下,链接可分为单链表、双向链表和循环链表三种常用类型。

一、单链表基本操作的实现

使用链式存储结构来实现的线性表称为链表。首元结点、头结点、头指针、空指针。

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\n",r->num);//输出最后出列人员编号 
47     free(r);//删除最后一个结点 
48 }
49 
50 int main()
51 {
52     int n,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 }

 输出结果:

posted @ 2017-05-10 20:28  王醒燕  阅读(513)  评论(0编辑  收藏  举报