静态链表


概念:

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

首先我们让数组的元素都是由两个数据域组成,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

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

posted @ 2015-02-04 17:04  stemon  阅读(489)  评论(0编辑  收藏  举报