【DS基础】静态链表

静态链表

目的:为没有指针的程序语言所设计的实现单链表的方法

静态链表(游标实现法)

数组的元素被分为两个数据域data和cur

静态链表的定义与初始化
/*静态链表定义*/
#define MAXSIZE 1000
typedef struct
{
    ElemType data;/*这里ElemType是数据域要存储的某种数据类型*/
    int cur;
}Component,StaticLinkList[MAXSIZE];/*快捷定义结构数组的方法*/
/*语句StaticLinkList A就等价于Component A[MAXSIZE]*/

数组的第一个元素cur存放**备用链表第一个结点的下标,数组最后一个元素cur存放数组第一个有数值元素的下标**(在全表为空时为0,类似于头指针的作用)。链表最后一个元素其下一位置数据为空cur用0表示。

/*静态链表初始化*/
Status InitList(StaticLinkList space)/*space是结构数组,space[0].cur为头指针*/
{
    int i;
    for(i=0;i<MAXSIZE-1;i++)
        space[i].cur=i+1;//将链表按照数组顺序指定
    space[MAXSIZE-1].cur=0;//更改最后一个链表指针
    return OK;
}

根据上述的下标规则,假设完成数据填入后的静态链表,其cur与下标的关系如图所示。

静态链表插入操作
  • 情况1:在尾端插入新元素
/*在尾端插入新元素*/
int Malloc_SLL(StaticLinkList space)
{
    int i=space[0].cur;/*获取备用链表第一个元素下标*/
    if(space[0].cur)
        space[0].cur=space[i].cur;/*调整第一个元素游标*/
    /*由于备用链表的第一个元素要被使用了,因此要将它的下一个元素作为备用链表的第一个元素*/
    return i;
}
  • **情况2:**在列表中间插入新元素:先插入到最后,在调整cur

例如在乙和丁之间插入丙,只需要先在下标7位置处存入丙,然后修改乙的游标指向丙,再修改丙的游标指向丁即可完成。

/*在静态链表L的第i个元素之前插入新的数据元素e*/
Syayis ListInsert(StaticLinkList L,int i,ElemType e)
{
    int j,k,l;
    k=MAX_SIZE-1;//k是最后一个元素的下标
    if(i<1||i>ListLength(L)+1)
        return ERROR;
    j=Malloc_SSL(L);//获取分配出的空闲元素的下标
    if(j)
    {
        L[j].data=e;//先把元素存入分配空间
        for(l=1;l<i-1;l++)
            k=L[k].cur;/*通过指针不断迭代的方式,找到第i个元素之前的下标*/
        L[j].cur=L[k].cur
        L[k].cur=j;
        return OK
    }
    return ERROR;
}
静态链表删除操作

简单描述为

1.脱链释放 将前后元素链接,完成释放。

如上图,无论是要删除已经使用的元素A,B还是C之中的一个,都先找到其上游元素。(遍历)如A的上游元素是末个元素。B的上游元素是A。

以删除B为例。找到上游元素,即A元素后,将其指向B的下一个元素C。如图。

2. 加入备用头 被释放元素成为备用链表首位元素。

​ 主要分为两步

  • 被释放元素指向原备用链表首元素
  • 数组首个元素指向该被释放元素

至此,B就被释放到了备用链表区域

/*删除在L中第i个数据元素e*/
Status ListDelete(StaticLinkList L,int i)
{
    int j,k;
    if(i<1||i>ListLength(L))//遍历法计算链表已使用元素个数
        return ERROR;
    k=MAX_SIZE-1;/*指向数组末个元素*/
    for(j=1;j<=i-1;j++)/*循环结束后,得到第i-1个元素的下标k*/
        k=L[k].cur;
    j=L[k].cur;/*j为第i个元素的下标*/
    L[k].cur=L[j].cur;//1.脱链释放
    Free_SSL(L,j);//2.加入备用头
    return OK;
}
void Free_SSL(StaticLinkList space,int k)
{
    space[k].cur=space[0].cur;/*2.1被释放元素指向原备用链表首元素*/
    space[0].cur=k;/*2.2数组首个元素指向该被释放元素*/
}

循环链表

将单链表终端的结点指针部分由空指针改为指向头结点,形成==循环链表(circular linked list)==

循环链表所解决的问题是,单链表由于其单向性,无法回溯。循环链表可以从任何一个结点触发,访问到链表的全部结点。

由于该结构访问最后一个结点效率太低,将头指针改为尾指针

双向链表

在单链表的每个结点中,再设置一个指向其前驱结点的指针域,形成==双向链表(double linked list)==。

结点中有两个指针域,一个指向直接后继,一个指向直接前驱

链表例题

链表逆转

题目来源:https://pintia.cn/problem-sets/15/problems/724

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); 
void Print( List L ); 
List Reverse( List L );

int main()
{
    List L1, L2;
    L1 = Read();
    std::cout<<"\033[0;32mread OK \033[0m"<<std::endl;
    L2 = Reverse(L1);
    std::cout<<"\033[0;32mreverse OK \033[0m"<<std::endl;
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */
List Read()
{
    int n,i;
    List L,p;
    p=L=(List)malloc(sizeof(Node));
    scanf("%d ",&n);//获取链表长度
    for(i=0;i<n;i++){
        p->Next=(List)malloc(sizeof(Node));
        p=p->Next;
        std::cin>>p->Data;//数据流格式读取的好处,可以同时匹配换行符或者空格分割的输入
    }
    p->Next=NULL;
    return L;
}
void Print( List L )
{
    while(L->Next!=NULL){
        L=L->Next;
        std::cout<<L->Data<<" ";
    }
    std::cout<<std::endl;
}
List Reverse(List L)
{   List p,q,r;
    p=L->Next;
    q=p->Next;
    r=q->Next;
    p->Next=NULL;
    while(r!=NULL)
    {   
        q->Next=p;
        p=q;
        q=r;
        r=q->Next;
    }
    q->Next=p;
    r=(List)malloc(sizeof(Node));
    r->Next=q;
 return r;
}
/*结果显示如下*/
1 3 4 5 2
read OK
reverse OK
1
2 5 4 3 1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值