数据结构与算法之静态链表(游标实现法)

介绍:为了让数组模拟单链表,数组元素都是由两个数据域组成,data,cur。也就是说,数组的每个下标都对应一个data和cur。数据域data,用来存放数据元素,也就是通常我们要处理的数据;而游标cur相当于单链表中的next指针,存放该元素后继在数组中的下标。我们把这种用数组描述的链表叫做静态链表,这种描述方法还叫做游标实现法。

原理说明:用于模拟链表的数组的第一个元素与最后一个元素作为特殊元素处理,数据域(data)不存放数据,第一个元素的索引域(cur)存放的是第一个备用元素的下标,最后一个元素的索引域存放的是第一个含有实际数据的数组元素的下标。

静态链表(游标实现法)
#include<stdio.h>

#define MAXSIZE 1000

typedef struct{

    int data;
    int cur;

}Component,StaticLinkList[MAXSIZE];

void InitList(StaticLinkList space)//静态链表初始化(space此时表示含有MAXSIZE个元素的数组)
{
    int i;

    for(i=0;i<MAXSIZE-1;i++)
    {
        space[i].cur = i+1;
    }

    space[MAXSIZE-1].cur = 0;//此时表示链表为空
}

//为静态链表“分配内存”,模拟malloc函数
int Malloc_SLL(StaticLinkList space)
{
    
    int i = space[0].cur;//space[0].cur用于存放模拟静态链表的数组剩余的元素中的第一个元素的下标。

    if(i)//如果i等于0表示链表已满。
    {
        //因为space[i]马上要被使用了,故在使用前把其下一个元素下标赋给静态链表的特殊结点。
        space[0].cur =  space[i].cur;
    }

    return i;
}

//为静态链表“释放内存”,模拟free函数
void Free_SSL(StaticLinkList space,int k)
{
    space[k].cur = space[0].cur;
    space[0].cur = k;
}

//计算静态链表的实际长度
int ListLength(StaticLinkList L)
{
    int j = 0;
    int i = L[MAXSIZE-1].cur;
    while(i)
    {
        i = L[i].cur;
        j++;
    }
    return j;
}

//往静态链表中插入元素
bool ListInsert(StaticLinkList L,int i,int e)
{
    int j,k,l;

    k = MAXSIZE-1;

    if(i<1||i>ListLength(L)+1)
    {
        return false;
    }

    j = Malloc_SLL(L);

    if(j)
    {
        L[j].data = e;

        for(l=1;l<=i-1;l++)
        {
            k = L[k].cur;
        }

        L[j].cur = L[k].cur;

        L[k].cur = j;

        return true;
    }

    return false;
}

//清空静态链表(目标:在逻辑上把静态表恢复到初始状态逻辑)
void ClearList(StaticLinkList space)
{
    int i,j,k;

    i = space[MAXSIZE-1].cur;//链表第一个有效结点的下标(特殊位置1)
    space[MAXSIZE-1].cur = 0;//首先将静态链表在形式上置为空

    k = space[0].cur;//备用链表第一个结点的下标(特殊位置2)
    space[0].cur = i;//将链表的第一个有效结点连到备用链表的表头

    //用于获取最后一个有效结点的下标
    while(i)
    {
        j = i;
        i = space[i].cur;
    }

    space[j].cur = k;//备用链表的第一个结点链接到链表的尾部(特殊位置3)
}

//销毁静态链表(同清空操作一致)
void DestoryList(StaticLinkList space)
{
    int i,j,k;

    i = space[MAXSIZE-1].cur;//链表第一个有效结点的下标
    space[MAXSIZE-1].cur = 0;//将链表在形式上置为空

    k = space[0].cur;//备用链表第一个结点的下标
    space[0].cur = i;//将链表的第一个有效结点连到备用链表的表头

    //用于获取最后一个有效结点的下标
    while(i)
    {
        j = i;
        i = space[i].cur;
    }

    space[j].cur = k;//备用链表的第一个结点链接到链表的尾部
}

//判断链表是否为空
bool ListEmpty(StaticLinkList space)
{
    if(space[MAXSIZE-1].cur==0)
        return true;
    else
        return false;
}

//获取静态链表中指定位置(位序,而不是下标)的元素
bool GetElem(StaticLinkList L,int i,int *e)
{
    int k,j;

    if(i<1||i>ListLength(L))
        return false;

    k = L[MAXSIZE-1].cur;//k此时为第一个有效结点的下标
    for(j=1;j<=i-1;j++)
    {
        k = L[k].cur;
    }
    *e = L[k].data;
    return true;
}

//获取指定元素在静态链表中的位置(不是位序,是数组下标)
int LocateElem(StaticLinkList L,int aim)
{
    int k=L[MAXSIZE-1].cur;
    
    //下面返回的是位序
    //int j=0,i;
    //for(i=1;i<ListLength(L);i++)
    //{ 
    //  k = L[k].cur;
    //  j++;
    //  if(L[k].data==aim)
    //      return j;
    //}
    //return -1;

    //返回位置(下标)
    while(k&&L[k].data!=aim)
    {
        k = L[k].cur;
    }
    return k;//如果值为0,则表示查找失败。
}

//获取静态链表指定元素的前驱
bool PriorElem(StaticLinkList L,int aim,int *pre_e)
{
    int k = L[MAXSIZE-1].cur;
    int j;

    while(k&&L[k].data!=aim)
    {
        j = k;
        k = L[k].cur;
    }
    
    if(k)//这一步很重要
    {
        *pre_e = L[j].data;

        return true;
    }

    return false;
    
}

//获取静态链表指定元素后继
bool NextElem(StaticLinkList L,int aim,int *next_e)
{

    //方法1
    int k = L[MAXSIZE-1].cur;
    int j=0;
    
    while(k&&L[k].data!=aim)
    {
        k = L[k].cur;
        j = L[k].cur;
    }
    if(k&&j)
    {
        *next_e = L[j].data;

        return true;
    }

    //方法2
    /*
    int j;
    int i = LocateElem(L,aim);//链表为空或者目标元素未查到,统统返回0
    if(i)
    {
        //如果i为静态链表最后一个有效元素的下标,则此时该下标所对应的元素不存在后继,j等于0.
        j = L[i].cur;

        if(j)
        {
            *next_e = L[j].data;
            return true;
        }
    }*/
    
    return false;
}

//删除静态链表指定位置的元素
bool ListDelete(StaticLinkList L,int i)
{
    int j,k=MAXSIZE-1;

    if(i<1||i>ListLength(L))
    {
        return false;
    }

    for(j=1;j<=i-1;j++){

        k = L[k].cur;
    }

    j = L[k].cur;
    L[k].cur = L[j].cur;
    Free_SSL(L,j);

    return true;
}

//遍历静态链表
void ListTraverse(StaticLinkList L)
{
    int k = L[MAXSIZE-1].cur;
    
    while(k)
    {
        printf("%d ",L[k].data);
        k = L[k].cur;
    }

    printf("\n");
}

int main()
{
    int i;
    int e,e0;
    StaticLinkList L;
    
    //静态链表初始化
    InitList(L);

    //向静态链表中插入数据
    for(i=1;i<10;i++)
    {
        if(!ListInsert(L,i,i+1))
        {
            printf("数据插入失败\n");
            return 0;
        }
    }

    //遍历静态链表
    printf("遍历静态链表元素如下:");
    ListTraverse(L);

    //判断链表是否为空
    /*
    if(ListEmpty(L))
    {
        printf("静态链表为空\n");
    }else
    {
        printf("静态链表不为空\n");
    }
    //清空链表
    ClearList(L);
    if(ListEmpty(L))
    {
        printf("静态链表为空\n");
    }*/
    
    //获取静态链表指定位置元素
    if(GetElem(L,2,&e))
    {
        printf("位序2上的元素为:%d\n",e);

    }else
    {
        printf("获取指定位置元素失败\n");
    }

    //获取指定元素的下标
    printf("值为9的元素在静态链表中的下标为:%d\n",LocateElem(L,9));//注意用来表示静态链表的数组是从下标1开始存储有效元素的。

    //获取指定元素的前驱
    if(PriorElem(L,8,&e0))
    {
        printf("静态链表中值为8的元素的前驱值为:%d\n",e0);
    }else
    {
        printf("你所指定的元素不存在前驱\n");
    }
    
    //获取指定元素的后继
    if(NextElem(L,8,&e0))
    {
        printf("静态链表中值为8的元素的后继值为:%d\n",e0);
    }else
    {
        printf("你所指定的元素不存在后继\n");
    }
    
    //获取指定位置
    if(GetElem(L,3,&e))
    {
        printf("静态链表位置3上的元素值为:%d\n",e);
    }
    else
    {
        printf("你所指定的位置不存在\n");
    }

    //删除静态链表指定位置元素
    if(ListDelete(L,4))
    {
        printf("执行删除操作后,静态链表中的元素如下:");
        ListTraverse(L);
    }
    else
    {
        printf("删除操作失败\n");
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容