• 静态链表



    概念:

    单链表的实现很好的借助了指针的作用,但是对一些早期的高级编程语言,他们没有指针,如果想实现单链表,就得用数组来代替指针。

    首先我们让数组的元素都是由两个数据域组成,data和cur。也就是说数组的每个下标都对应一个data和一个cur。cur相当于单链表中的next指针,存放该元素的后继在数组中的下标。

    我们把这种数组描述的链表叫做静态链表。


    实现规则:

    对数组的第一个和最后一个元素结点做特殊处理,他们不存放数据。通常把未被使用的数组元素成为备用链表,数组的第一个元素,即下标为0的元素的cur就存放备用链表的第一个结点的下标;而数组的最后一个元素的cur则存放第一个有数值的元素的下标,相当于单链表中的头结点的作用。

    当整个链表为空时,如下图所示:

    image

    数组的最后一个元素指向第一个有数据的元素的下标,对于空表来说,它的cur等于0,代表后面没有元素,类似于NULL。

    而对于有数据的静态链表,如下图所示:

    image

    最后一个有值元素,它的游标cur设置为0。同样,如果下标为0的元素的cur等于0,代表没有备用的链表可以使用。


    静态链表的插入和删除:

    静态链表中要解决的问题是:如何用静态模拟动态链表结构的存储空间的分配,需要的时候申请,不需要的时候释放,类似C语言的malloc和free这两个函数。这里就要自己实现这两个函数,对已用链表和备用链表这两个链表做相应的操作。

    现在如果我们需要在“乙”和“丁”之间插入一个值为“丙”的元素,只需要将“乙”的cur改为7,表示下一位是“丙”,并将“丙”的cur改为3,表示下一位是丁。

    image

    现在如果我们删除了第一个元素“甲”,表示现在“甲”这个位置空出来了,如果未来有新人要来则优先考虑这里,所以删除的位置成为第一个优先空位,即首元素的cur为1, 下标为1的元素的cur改为8,而下标为8的位置cur改为9,最后元素位置的cur改为2。

    image


    代码实现:

    #include <iostream>
    #include <stdlib.h>
    using namespace std;
    
    #define MAXSIZE 100
    typedef int ElemType;
    /*线性表的静态链表存储结构*/
    typedef struct 
    {
        ElemType data;
        int cur;//为0时表示没有后继的元素,类似于NULL
    }StaticLinkList[MAXSIZE];
    
    /*将一维数组array中各个分量链成一个备用链表,array[0].cur为头指针,“0”表示空指针*/
    bool InitList(StaticLinkList array)
    {
        cout << "InitList..." << endl;
        for(int i = 0; i < MAXSIZE - 2; i++)
        {
            array[i].cur = i + 1;
        }
        array[MAXSIZE - 2].cur = 0;/*最后一个元素是不可以用的,倒数第二个元素的cur为0,表示备用链表的结尾NULL*/
        array[MAXSIZE - 1].cur = 0;/*目前链表为空表,最后一个元素的cur为0*/
    
        return true;
    }
    
    /*若备用链表非空,则返回分配的结点下标,否则返回0*/
    int Malloc_SLL(StaticLinkList array)
    {
        int i = array[0].cur;
        if(i != 0)
        {
            array[0].cur = array[i].cur;/*下一个空结点用来作备用*/
        }
    
        return i;
    }
    
    /*将下标为k的空闲结点回收到备用链表*/
    void Free_SLL(StaticLinkList array, int k)
    {
        array[k].cur = array[0].cur;/*把第一个元素的cur值赋值给要删除元素的cur*/
        array[0].cur = k;/*把要删除元素的下标赋值给第一个元素的cur值    */
    }
    
    /*获取静态链表中元素的个数*/
    int ListLength(StaticLinkList array)
    {
        int count = 0;
        int index = array[MAXSIZE - 1].cur;
        while(index != 0)
        {
            count++;
            index = array[index].cur;
        }//while
    
        return count;
    }
    
    /*在array中第pos个元素之前插入新的数据元素elem*/
    bool ListInsert(StaticLinkList array, int pos, ElemType elem)
    {
        cout << "Insert List from pos: " << pos << "Item" << elem << endl;
        if(pos < 1 || pos > ListLength(array) + 1)/*1<=pos<=ListLength(array)+1*/
        {
            return false;
        }
        int index = MAXSIZE - 1;
        int k = Malloc_SLL(array);/*获取空闲分量的下标*/
        if(k)
        {
            array[k].data = elem;
    
            for(int i = 1; i < pos; i++)
            {
                index = array[index].cur;
            }
            array[k].cur = array[index].cur;/*把第pos个元素之前的那个元素的cur赋值给新元素的cur*/
            array[index].cur = k;/*把新元素的下标赋值给第pos个元素之前的元素的cur*/
    
            return true;
        }
    
        return false;
    }
    
    /*删除array中第pos个数据元素*/
    bool ListDelete(StaticLinkList array, int pos)
    {
        cout << "Delete List from pos: " << pos << endl;
        if(pos < 1 || pos > ListLength(array))
        {
            return false;
        }
        
        int index = MAXSIZE - 1;
        for(int i = 1; i < pos; i++)//定位到第pos个元素之前的那个元素
        {
            index = array[index].cur;
        }
        int tempIndex = array[index].cur;
        array[index].cur = array[tempIndex].cur;
        Free_SLL(array, tempIndex);
    
        return true;
    }
    
    bool ListTraverse(StaticLinkList array)
    {
        cout << "List Traverse: " << endl;
        int index = MAXSIZE - 1;
        
        while(array[index].cur != 0)
        {
            index = array[index].cur;
            cout << array[index].data << ' ';
        }
        cout << endl;
    
        return true;
    }
    
    int main(void)
    {
        StaticLinkList SLL;
        InitList(SLL);
        for(int i= 1; i < 
    11
    ; i++)
        {
            ListInsert(SLL, i, i);
        }
    
        ListTraverse(SLL);
    
        ListDelete(SLL, 3);
        ListTraverse(SLL);
        cout << "List Length:" << ListLength(SLL) << endl;
    
        system("pause");
        return 0;
    }

    程序运行结果:

    image

    静态链表在插入和删除操作时不需要移动元素,只需要修改游标,从而改进了在顺序结构中插入和删除操作需要移动大量元素的缺点;但是没有解决连续分配存储带来的表长难以确定的问题;并且失去了顺序存储结构随机存取的特性。

  • 相关阅读:
    JavaScript 把函数作为参数进行传值
    面向微服务的企业云计算架构转型
    bzoj1009 GT考试 (kmp+矩阵优化dp)
    noiac64 sort (二分答案)
    luogu1983 车站分级 (拓扑排序)
    loj6157 A ^ BProblem (并查集)
    bzoj1831 逆序对 (dp+树状数组)
    luogu2282/bzoj1219 历史年份 (dp+hash+二分+线段树)
    bzoj3702/bzoj2212 二叉树 (线段树合并)
    cf1073G Yet Another LCP Problem (SA+权值线段树)
  • 原文地址:https://www.cnblogs.com/stemon/p/4272808.html
Copyright © 2020-2023  润新知