zoukankan      html  css  js  c++  java
  • 数据结构(二)线性表——链表

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

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

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

    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 }

     输出结果:

  • 相关阅读:
    重构与反思-<重构代码的7个阶段>有感
    Unity 自定义"=="操作符 [翻译来源blogs.unity3d,2014/05]
    Unity UGUI Button 无法点击问题一例
    [Lua性能] 小试验一例
    C# 循环中 直接索引 VS 缓存索引 性能测试
    Lua table直接索引VS缓存索引性能测试小示例
    大型网站架构系列:负载均衡详解(1)
    大型网站架构系列:电商网站架构案例(3)
    大型网站架构系列:电商网站架构案例(2)
    大型分布式网站架构技术总结
  • 原文地址:https://www.cnblogs.com/wxywxy/p/6837946.html
Copyright © 2011-2022 走看看