美文网首页
线性表(静态链表)

线性表(静态链表)

作者: lkmc2 | 来源:发表于2018-07-24 22:23 被阅读86次

线性表:包含零个或多个数据元素的有限序列。

线性链表:指的是使用数组代替指针,来描述单链表;每个数据项含有data和cur属性,data是数据的值,cur相当于指向下一个节点的指针。

线性表特性:

  • 是一个序列,元素直接是有顺序的。
  • 表中元素个数叫表长,元素个数可以有多个,也可以为0。
  • 某个元素的上一个元素叫直接前驱元素,下一个元素叫直接后继元素。

链式存储结构特点
使用带数据域和指针域的节点存储单个元素的值,并通过指针将所有元素连接起来。

优点:

  • 拥有单链表类似的特性。
  • 插入和删除元素的时候,只需要修改游标。
  • 改进了顺序存储结构中插入和删除操作需要大量移动元素的缺点。

缺点:

  • 没有解决连续存储分配带来的表长难以确定的问题。
  • 失去了顺序存储结构随机存取的特性。

时间复杂度

  • 读取时的时间复杂度为O(n)。
  • 插入、删除时的时间复杂度为O(1)。
数据项示意图 空静态链表示意图 静态链表插入元素示意图 静态链表删除元素示意图

实现代码如下:

// 线性表(静态链表)
#include <stdio.h>
#include <malloc.h>
#include <time.h>

#define OK 1      // 执行成功
#define ERROR 0   // 执行失败

#define MAXSIZE 100 // 初始分配存储空间

typedef int Status; // 函数返回结果类型
typedef char ElemType; // 元素类型

/**
 * 静态链表结构
 * 1. 数组最后一个元素的cur用来存放第一个插入元素的下标,
 *    相当于头节点,指向0时表示链表为空
 * 2. 数组0下标元素的cur用来存放下一个可用存储位置的下标,
 *    即下一个插入节点的位置
 */
typedef struct {
    ElemType data; // 存放元素值
    int cur; // 指向下一个节点的下标,为0表示无指向,即到达链表末尾
} Component, StaticLinkList[MAXSIZE];

/**
 * 初始化静态链表
 * 将一维数组L的分量链接成一个备用链表,L[0].cur为头指针,0表示空指针
 * @param L 静态链表
 * @return 执行状态
 */
Status InitList(StaticLinkList L) {
    int i; // 用于遍历表元素

    for (i = 0; i < MAXSIZE - 1; i++) {
        L[i].cur = i + 1; // 设置每个位置的指针指向下一个元素的位置
    }
    // 链表中最后一个元素指向0(表示当前第一个插入的节点下标为0,此时链表为空)
    L[MAXSIZE - 1].cur = 0;
    return OK;
}

/**
 * 获取下一个可用存储位置的下标
 * @param L 静态链表
 * @return 下一个可用存储位置的下标,无可用存储位置时返回0
 */
int Malloc_SSL(StaticLinkList L) {
    int i = L[0].cur; // L中0位置cur存的值就是下一个可用存储位置的下标

    // 当前静态链表未满
    if (L[0].cur) {
        L[0].cur = L[i].cur; // 获取下一个可用存储位置的下标
    }
    return i; // 返回下一个可用存储位置的下标
}

/**
 * 释放下标为k的元素到备用链表
 * 即让下标为k的元素成为下一个可插入节点
 * @param L 静态链表
 * @param k 元素下标
 */
void Free_SSL(StaticLinkList L, int k) {
    L[k].cur = L[0].cur; // 让k下标元素的下一个元素指向原本的下一个可插入节点
    L[0].cur = k; // 让k下标的元素成为下一个可插入节点
}

/**
 * 获取线性链表长度
 * @param L 线性链表
 * @return 线性链表长度
 */
int ListLength(StaticLinkList L) {
    int j = 0; // 用于统计元素个数
    int i = L[MAXSIZE - 1].cur; // 获取第一个元素的下标

    // 遍历链表元素
    while (i) {
        i = L[i].cur; // 获取下一个元素的下标
        j++; //统计个数加1
    }
    return j; // 返回链表长度
}

/**
 * 在线性链表中指定位置插入新元素
 * @param L 线性链表
 * @param i 插入位置
 * @param e 插入的值
 * @return 执行状态
 */
Status ListInsert(StaticLinkList L, int i, ElemType e) {
    int j, t; // j是下一个可插入位置的下标,t用于遍历for循环

    int k = MAXSIZE - 1; // 最后一个元素的下标

    // 插入位置下标越界,插入失败
    if (i < 1 || i > ListLength(L) + 1) {
        return ERROR;
    }

    j = Malloc_SSL(L); // 获取下一个可插入位置的下标

    // 线性链表未满(j不为0)
    if (j) {
        L[j].data = e; // 将e赋值给下一个可插入节点的值(j下标的元素表示新节点)

        // 遍历线性链表,找到插入位置的上一个节点
        for (t = 1; t <= i - 1; t++) {
            k = L[k].cur; // 获取下一个元素的坐标
        }

        L[j].cur = L[k].cur; // 新节点的指向插入位置前一个元素的下一个元素(即原本i位置的节点)
        L[k].cur = j; // 插入位置的上一个节点指向新节点
        return OK;
    }
    return ERROR;
}

/**
 * 删除线链性表中指定位置的元素
 * @param L 线性链表
 * @param i 删除位置的下标
 * @return 执行状态
 */
Status ListDelete(StaticLinkList L, int i) {
    int j; // 用于遍历元素

    int k = MAXSIZE - 1; // 最后一个元素的下标

    // 插入位置下标越界,插入失败
    if (i < 1 || i > ListLength(L) + 1) {
        return ERROR;
    }

    // 遍历线性链表,找到删除位置的上一个节点
    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 OK;
}

/**
 * 打印单个元素
 * @param e 元素值
 * @return 执行状态
 */
Status visit(ElemType e) {
    printf("%c ", e);
    return OK;
}

/**
 * 遍历输出线性链表中所有元素
 * @param L 线性链表
 * @return 执行状态
 */
Status ListTravel(StaticLinkList L) {
    int i = L[MAXSIZE - 1].cur; // 获取链表第一个元素的下标

    printf("[ ");
    // 遍历链表中所有元素
    while (i) {
        visit(L[i].data); // 打印单个节点的值
        i = L[i].cur; // 获取下一个节点的下标
    }
    printf("]\n");
    return OK;
}

int main() {
    StaticLinkList L; // 线性链表
    Status status; // 执行状态

    status = InitList(L); // 初始化线性链表

    printf("初始化后,L的长度为:%d\n", ListLength(L));

    status = ListInsert(L, 1, 'F');
    status = ListInsert(L, 1, 'E');
    status = ListInsert(L, 1, 'D');
    status = ListInsert(L, 1, 'B');
    status = ListInsert(L, 1, 'A');

    printf("在L的表头分别插入五个元素后,L中的值为:");
    ListTravel(L); // 遍历链表元素
    printf("L的长度为:%d\n", ListLength(L));

    status = ListInsert(L, 3, 'C'); // 在第三个位置插入C元素
    printf("在第三个位置插入一个元素C后,L中的值为:");
    ListTravel(L); // 遍历链表元素
    printf("L的长度为:%d\n", ListLength(L));

    status = ListDelete(L, 4); // 删除第四个位置的元素
    printf("删除第四个位置的元素D后,链表L中的值为:");
    ListTravel(L); // 遍历链表元素
    printf("L的长度为:%d\n", ListLength(L));

    return 0;
}
运行结果

相关文章

  • 数据结构与算法之数组与链表

    线性表包括数组,链表(单链表,双向链表,循环链表,双向循环链表,静态链表),栈(顺序栈,链式栈),队列(普通队列,...

  • 数据结构与算法之栈与队列

    线性表包括数组,链表(单链表,双向链表,循环链表,双向循环链表,静态链表),栈(顺序栈,链式栈),队列(普通队列,...

  • 数据结构之线性表(下)

    单链表:通过指针连接的线性表 没有指针的语言如果表示链表?答案是静态链表,静态链表用数组表示,使用元素的物理位序来...

  • 数据结构——线性表

    线性表分为顺序存储结构和链式存储结构(单链表,静态链表,循环链表,双向链表)。 单链表(**一种动态结构,所占空间...

  • 线性表

    线性表是零个或者多个具有相同的数据元素的有限序列。 线性表的二大结构:顺序存储结构、链式存储结构(单链表、静态链表...

  • 线性表

    1.线性表 1.1 顺序表(顺序存储) 静态分配 动态分配 1.2 单链表 单链表定义 不带头节点的单链表插入操作...

  • 线性表(静态链表)

    线性表:包含零个或多个数据元素的有限序列。 线性链表:指的是使用数组代替指针,来描述单链表;每个数据项含有data...

  • 线性表 - 静态链表

    下面查看静态链表的几种状态

  • PHP 实现数据结构

    参考诸多视频和文章,主要通过PHP 实现线性表的顺序存储结构,单链表,静态链表,双向链表以及二叉树等数据结构,代码...

  • 数据结构-单向链表

    一、线性表 线性表可以分为: 顺序表(数组) 链表(单向链表、双向链表、循环链表) 二、链表 链表是一种链式存储的...

网友评论

      本文标题:线性表(静态链表)

      本文链接:https://www.haomeiwen.com/subject/gequmftx.html