《数据结构》| 链表的具体实现(超详细)


与你相识


博主介绍:

– 本人是普通大学生一枚,每天钻研计算机技能,CSDN主要分享一些技术内容,因我常常去寻找资料,不经常能找到合适的,精品的,全面的内容,导致我花费了大量的时间,所以会将摸索的内容全面细致记录下来。另外,我更多关于管理,生活的思考会在简书中发布,如果你想了解我对生活有哪些反思,探索,以及对管理或为人处世经验的总结,我也欢迎你来找我。

– 目前的学习专注于Go语言,辅学算法,前端领域。也会分享一些校内课程的学习,例如数据结构,计算机组成原理等等,如果你喜欢我的风格,请关注我,我们一起成长。


Introduction

本节主要解决线性表在链式储存这种物理结构下的具体实现,涉及到单链表,循环链表,双向链表,时间复杂度分析。



具体实现就是把数据结构这种结构填充上具体的数据,落在实处了,需要去做一些具体的操作,比如光有加减乘除,没有任何意义,但是加减乘除遇上数字就有了意义,我们我们学习的顺序表这种数据结构就仅仅是一种结构,我们需要让它实际的能够处理问题。

单链表

单链表的设计过程是比较艰难的,第一是对语言的不熟悉(指针和内存的理解不透彻),第二是链表本身的思维和平常的思维不同,结点的互相交叉容易让人晕掉。不过也没有办法,唯手熟尔。

不带头结点的单链表

/*
 * 不带头结点的链表
 */

/*
 * 结构体构造
 */
typedef struct Node {
    int data;
    int length;
    struct Node *next;
} LinkNode, *LinkedList;


/*
 * 创建一个结点
 */
Node *InitList(int data) {
    LinkNode *node = (LinkNode *) malloc(sizeof(LinkNode));
    node->next = NULL;
    node->length = 1;
    node->data = data;
    return node;
}

/*
 * 判断是否为空
 */
bool ListEmpty(LinkedList L) {
    return L->length == 0;
}

/*
 * 返回链表的长度
 */
int Length(LinkedList L) {
    return L->length;
}

/*
 * 销毁链表
 */
void DestroyList(LinkedList &L) {
    // 1. 判断是否为空
    if (ListEmpty(L)) {
        return;
    }
    // 2. 创建有工程结点
    LinkNode *node;
    // 3. 循环释放结点
    while (L != NULL) {
        node = L->next;
        free(&node);
        L = node;
    }
}

/*
 * 获取元素
 */
void GetElem(LinkedList L, int index, LinkNode &element) {
    // 判断是否为空,以及index是否合法
    if (ListEmpty(L) || index < 1 || index > L->length) {
        return;
    }
    // 循环获取元素并赋值
    LinkedList L2 = L;
    for (int i = 1; i < index; i++) {
        L2 = L2->next;
    }

    element = *L2;
}

/*
 * 若包含元素,返回下标
 */
int LocateElem(LinkedList L, int element) {
    // 判断是否为空
    if (ListEmpty(L)) {
        return -1;
    }
    // 循环比较元素的值
    LinkedList L2 = L;
    for (int i = 0; i < L->length; i++) {
        if (L2->data == element) {
            return i + 1;
        }
        L2 = L2->next;
    }
    return -1;
}

/*
 * 返回前驱
 */
void PriorElem(LinkedList L, int cur_e, int &pre_e) {
    // 找到cur_e元素的下标
    int result = LocateElem(L, cur_e);
    if (result == -1) {
        return;
    }
    // 判断result是否是第一个元素
    if (result == 1) {
        return;
    }
    // 获取前驱元素
    LinkNode pre;
    GetElem(L, result - 1, pre);
    pre_e = pre.data;
}

/*
 * 返回后继
 */
void NextElem(LinkedList L, int cur_e, int &next_e) {
    // 找到cur_e元素的下标
    int result = LocateElem(L, cur_e);
    if (result == -1) {
        return;
    }
    // 判断result是否是最后一个元素
    if (result == L->length) {
        return;
    }
    // 获取后继元素
    LinkNode next;
    GetElem(L, result + 1, next);
    next_e = next.data;
}

/*
 * 添加元素
 */
void ListInsert(LinkedList &L, int index, int element) {
    // 1. 判断index是否合法.index=1是首个元素的地址,index=length + 1是在最后加元素  TODO length + 1
    if (index < 1 || index > L->length + 1) {
        return;
    }
    // 2. 创建一个结点,以及复制一份LinkedList
    LinkNode *node = InitList(element);
    LinkedList L2 = L;
    int length = L->length;
    // 4. 判断是否是为头部添加元素,如果是的话,需要维护L指针
    if (index == 1) {
        node->next = L;
        L = node;
        L->length = length + 1;
        return ;
    }
    // 3. 循环到要添加的的位置的前一个,把元素添加进去
    for (int i = 1; i < index - 1; i++) {
        L2 = L2->next;
    }
    // 4. 插入结点
    node->next = L2->next;
    L2->next = node;
    L->length ++;
}

/*
 * 删除元素
 */
void ListDelete(LinkedList &L, int index) {
    // 1. 检查下标是否合法
    if(ListEmpty(L) || index < 1 || index > L->length) {
        return;
    }
    // 2. 是否是删除第一个元素?  如果是,需要对头指针进行特殊处理。
    int length = L->length;
    if (index == 1) {
        L = L->next;
        L->length = length - 1;
        return;
    }
    // 3. 得到下标的前驱结点,然后删除结点
    LinkedList L2 = L;
    for (int i = 0; i < index - 1; i ++) {
        L2 = L2->next;
    }
    L2->next = L2->next->next;
    L->length = length - 1;
}

/*
 * 遍历列表
 */
void TraverseList(LinkedList L) {
    // 1. 如果结点为NULL,退出
    if (L == NULL) {
        return;
    }

    // 2. 遍历各个结点,输出data
    // 格式:1 -> 2 -> 3 -> NULL
    LinkedList L2 = L;
    for (int i = 0; i < L->length; i++) {
        std::cout << L2->data;
        std::cout << " -> ";
        L2 = L2->next;
    }
    std::cout << "NULL" << std::endl;
}

// 测试函数
int main() {
    LinkedList l1 = InitList(3);
    std::cout << ListEmpty(l1) << std::endl;
    ListInsert(l1, 1, 1);
    TraverseList(l1);
    ListInsert(l1, 2, 2);
    TraverseList(l1);
    ListInsert(l1, 1, 3);
    TraverseList(l1);
    std::cout << Length(l1) << std::endl;
    LinkNode l2;
    GetElem(l1,1,l2);
    int s = LocateElem(l1,1);
    int prior;
    PriorElem(l1,1,prior);
    int next;
    NextElem(l1,3,next);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    DestroyList(l1);
    TraverseList(l1);
    return 0;
}

结果:
0
1 -> 3 -> NULL
1 -> 2 -> 3 -> NULL
3 -> 1 -> 2 -> 3 -> NULL
4
1 -> 2 -> 3 -> NULL
2 -> 3 -> NULL
3 -> NULL

带头结点的单链表

// 带头结点的单链表操作

/*
 * 结点struct
 */
typedef struct Node {
    int data;  // value
    int length; // 链表的长度(用一个变量来存储,可以减少获取长度的麻烦)
    struct Node *next;  // 下一个节点的地址,因为存的是地址,所以要用指针类型。
} LinkNode, *LinkedList;  // 因为链表本身就是一个头结点的地址,所以用*LinkNode来表示结点。用LinkedList来表示链表。

/*
 * 头插法创建单链表
 */
LinkNode *InitListHead() {
    // 1. 创建一个头节点
    LinkNode *node = (LinkNode *) malloc(sizeof(LinkNode));
    // 2. 初始化头节点的值和next
    node->data = -1;
    node->next = NULL;
    node->length = 0;
    // 3. 返回头结点
    return node;
}

/*
 * 销毁链表(释放所有节点)
 */
void DestroyList(LinkedList &L) {
    // 销毁链表
    LinkNode *l1;
    while (L != NULL) {
        // 记录L的下一个结点
        l1 = L->next;
        // 将当前L结点释放
        free(&L);
        // 让L等于l1
        L = l1;
    }
}

/*
 * 判断是否为空
 */
bool ListEmpty(LinkedList L) {
    return L->length == 0;
}

/*
 * 返回链表的长度
 */
int Length(LinkedList L) {
    return L->length;
}

/*
 * 获取第i个元素的值,返回的是struct
 */
void GetElem(LinkedList L, int index, LinkNode &e) {
    // 1. 判断索引是否越界
    // 如果索引 = 0,是头地址,没有意义,如果大于Length,没有元素,也没有意义。
    if (index < 0 || index > L->length) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 2. 循环链表,获取数据
    for (int i = 0; i < index; i++) {
        L = L->next;
    }
    // 3. 此时的L就是我们想要的结点,赋值
    e = *L;
}

/*
 * 返回列表中第1个值与e相同的元素的下标,若不存在返回-1
 */
int LocateElem(LinkedList L, int e) {
    // 1. 判断是否为空
    if (ListEmpty(L)) {
        std::cout << "Get failed. The list is empty." << std::endl;
        return -1;
    }
    LinkedList L2 = L;
    // 2. 循环链表,获取数据
    for (int i = 0; i < L->length; i++) {
        L2 = L2->next;
        if (L2->data == e) {
            return i + 1;
        }
    }
    // 3. 没找到,返回-1
    return -1;
}

/*
 * 获取前驱
 */
void PriorElem(LinkedList L, LinkNode cur_e, LinkNode &pre_e) {
    // 1. 获取cur_e结点的index
    int index = LocateElem(L, cur_e.data);
    // 2. 如果没找到这个结点,返回错误信息
    if (index == -1) {
        std::cout << "Get failed. current element is not find." << std::endl;
        return;
    }
    // 3. 第一个结点没有前驱结点
    if (index == 1) {
        std::cout << "Get failed. current element is fist of the List." << std::endl;
        return;
    }
    // 4. 通过GetElem获取这个结点的index - 1的节点(即前驱)
    GetElem(L, index - 1, pre_e);
}

/*
 * 获取后继
 */
void NextElem(LinkedList L, LinkNode cur_e, LinkNode &next_e) {
    // 1. 获取cur_e结点的index
    int index = LocateElem(L, cur_e.data);
    // 2. 如果没找到这个结点,返回错误信息
    if (index == -1) {
        std::cout << "Get failed. current element is not find." << std::endl;
        return;
    }
    // 3. 最后一个结点没有后继结点
    if (index == L->length) {
        std::cout << "Get failed. current element is last of the List." << std::endl;
        return;
    }
    // 4. 通过GetElem获取这个结点的index + 1的节点(即后继)
    GetElem(L, index + 1, next_e);
}

/*
 * 在链表的index位置添加结点
 */
void ListInsert(LinkedList L, int index, int e) {
    // 1. 判断index是否合法
    // 如果索引 < 1,是头地址或之前的元素,没有意义,如果大于Length + 1,也没有意义。
    // 当index = 1时为头添加元素,当index=length + 1的时候,为尾添加元素
    if (index < 1 || index > L->length + 1) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 2. 获取index - 1位置的节点。   a b 两个结点,我们要在b前面添加一个结点,我们需要先获取a结点
    LinkedList L2 = NULL;
    L2 = L;
    for (int i = 0; i < index - 1; i++) {
        L2 = L2->next;
    }
    // 3. 插入结点  a b 两个结点,temp = a,得到a结点就可以得到b结点
    // 创建要插入的结点
    LinkNode *insertElem = InitListHead();
    insertElem->data = e;
    // 将结点插入
    insertElem->next = L2->next;
    L2->next = insertElem;
    L->length++;
}

/*
 * 删除节点
 */
void ListDelete(LinkedList L, int index) {
    // 1. 判断index是否合法
    // 如果索引 < 1,是头地址或之前的元素,没有意义,如果大于Length,也没有意义。 (没有元素)
    if (index < 1 || index > L->length) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 初始化这个节点
    LinkNode *temp = L;
    for (int i = 0; i < index - 1; i++) {
        temp = temp->next;
    }
    LinkNode *preNode = temp;
    preNode->next = preNode->next->next;
    L->length--;
}

/*
 * 对线性表进行遍历
 */
void TraverseList(LinkedList L) {
    // 1. 遍历各个结点,输出data
    // 格式:1 -> 2 -> 3 -> NULL
    int length = L->length;
    for (int i = 0; i < length; i++) {
        L = L->next;
        std::cout << L->data;
        std::cout << " -> ";
    }
    std::cout << "NULL" << std::endl;
}

// 测试函数
int main() {
    LinkedList l1 = InitListHead();
    std::cout << ListEmpty(l1) << std::endl;
    ListInsert(l1, 1, 1);
    TraverseList(l1);
    ListInsert(l1, 2, 2);
    TraverseList(l1);
    ListInsert(l1, 3, 3);
    TraverseList(l1);
    std::cout << Length(l1) << std::endl;
    LinkNode l2;
    GetElem(l1,1,l2);
    int s = LocateElem(l1,1);
    LinkNode prior;
    PriorElem(l1,l2,prior);
    LinkNode next;
    NextElem(l1,l2,next);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    DestroyList(l1);
    TraverseList(l1);
    return 0;
}

结果:
1
1 -> NULL
1 -> 2 -> NULL
1 -> 2 -> 3 -> NULL
3
Get failed. current element is fist of the List.
2 -> 3 -> NULL
3 -> NULL
NULL

循环链表

带头结点的循环链表


/*
 * 带头结点的循环单链表
 */

/*
 * 构造结构体
 */
typedef struct Node {
    int data;  // value
    struct Node *next;  // 下一个结点
} LinkNode, *LinkedList;

/*
 * 创建一个新结点并返回
 */
LinkedList InitList() {
    LinkNode *node = (LinkNode *) malloc(sizeof(LinkNode));
    node->next = node;
    node->data = -1;

    return node;
}

/*
 * 判断是否为空
 */
int ListEmpty(LinkedList L) {
    if (L->next == L) {
        return 1;
    }
    return 0;
}

/*
 * 获取长度
 */
int ListLength(LinkedList L) {
    int count = 0;
    LinkedList L2 = L;
    while (L2->next != L) {
        count++;
        L2 = L2->next;
    }

    return count;
}

/*
 * 添加元素
 */
void ListInsert(LinkedList L, int index, int element) {
    int length = ListLength(L);
    // 1. 处理指针违法问题
    if (L == NULL || index < 1 || index > length + 1) {
        return;
    }
    // 2. 创建一个新结点
    LinkNode *node = (LinkNode *) malloc(sizeof(LinkNode));
    node->data = element;
    // 复制一份链表
    LinkedList L2 = L;
    // 3. 插入结点
    for (int i = 1; i < index; i++) {
        // 得到要插入的前驱结点
        L2 = L2->next;
    }
    node->next = L2->next;
    L2->next = node;
}

/*
 * 遍历链表
 */
void TraverseList(LinkedList L) {
    // 1. 如果结点为NULL,退出
    if (L == NULL) {
        return;
    }

    // 2. 遍历各个结点,输出data
    // 格式:1 -> 2 -> 3 -> NULL
    LinkedList L2 = L;
    int length = ListLength(L);
    for (int i = 0; i < length + 1; i++) {
        std::cout << L2->data;
        std::cout << " -> ";
        L2 = L2->next;
    }
    std::cout << std::endl;
}

/*
 * 用e返回L中第i个元素的值
 */
void GetElem(LinkedList L, int index, int &elem) {
    int length = ListLength(L);
    // 1. 判断条件是否合法
    if (L == NULL || index < 1 || index > length) {
        return;
    }
    // 2. 返回元素值
    LinkedList L2 = L;
    for (int i = 0; i < index; i++) {
        L2 = L2->next;
    }
    elem = L2->data;
}

/*
 * 查询元素是否包含,如果包含返回下标,否则返回-1
 */
int LocateElem(LinkedList L, int elem) {
    // 1. 判断是否为空,如果为空,没必要进行下面的运算
    if (ListEmpty(L)) {
        return -1;
    }
    // 2. 获取链表长度
    int length = ListLength(L);
    // 3. 让L2等于第一个元素
    LinkedList L2 = L->next;
    // 4. 遍历链表
    for (int i = 0; i < length; i++) {
        // 如果data是我们找的元素,返回这个索引
        if (L2->data == elem) {
            return i + 1;
        }
        // 把L2递进到下一个元素
        L2 = L2->next;
    }
    return -1;
}

/*
 * 返回前驱
 */
void PriorElem(LinkedList L, int cur_e, int &pre_e) {
    // 1. 获取当前元素的下标
    int curNode = LocateElem(L, cur_e);
    // 2. 返回值可能是0(找到了头结点)或-1(没有找到这个结点),或1(第一个结点),都返回,没有意义。
    if(curNode < 2) {
        return;
    }
    // 3. 创建一个新链表
    LinkedList L2 = L;
    // 4. 建立一个循环,把L2递进到cur_e的前驱位置
    for (int i = 0; i < curNode - 1; i++) {
        L2 = L2->next;
    }
    // 5. 获取到这个前驱的值
    pre_e = L2->data;
}

/*
 * 返回后继
 */
void NextElem(LinkedList L, int cur_e, int &next_e) {
    int length = ListLength(L);
    // 1. 获取当前元素的下标
    int curNode = LocateElem(L, cur_e);
    // 2. 返回值可能是0(找到了头结点)或-1(没有找到这个结点),没有意义。 或者curNode == length是尾结点,没有后继。
    if(curNode < 1 || curNode == length) {
        return;
    }
    // 3. 创建一个新链表
    LinkedList L2 = L;
    // 4. 建立一个循环,把L2递进到cur_e的前驱位置
    for (int i = 0; i < curNode + 1; i++) {
        L2 = L2->next;
    }
    // 5. 获取到这个前驱的值
    next_e = L2->data;
}

/*
 * 删除元素
 */
void ListDelete(LinkedList L, int index) {
    int length = ListLength(L);
    // 1. 判断条件是否合法
    if (L == NULL || index < 1 || index > length) {
        return;
    }
    // 2. 删除元素
    LinkedList L2 = L;
    for (int i = 0; i < index - 1; i++) {
        L2 = L2->next;
    }
    // 3. 转移next
    L2->next = L2->next->next;
}

int main() {
    LinkedList l1 = InitList();
    std::cout << ListEmpty(l1) << std::endl;
    std::cout << ListLength(l1) << std::endl;
    ListInsert(l1, 1, 1);
    TraverseList(l1);
    ListInsert(l1, 2, 2);
    TraverseList(l1);
    ListInsert(l1, 3, 3);
    TraverseList(l1);
    std::cout << ListLength(l1) << std::endl;
    int l2;
    GetElem(l1, 3, l2);
    int s = LocateElem(l1, 2);
    int prior;
    PriorElem(l1, l2, prior);
    int next;
    NextElem(l1, 2, next);
    ListDelete(l1, 1);
    TraverseList(l1);
    ListDelete(l1, 1);
    TraverseList(l1);
    ListDelete(l1, 1);
    TraverseList(l1);
    return 0;
}

双向链表


#include <iostream>
#include <cstdlib>

/*
 * 带头结点的双向链表
 */
typedef struct Node {
    int data;
    struct Node *prior,*next;
}LinkNode, *LinkedList;

/*
 * 构造一个空链表
 */
LinkNode *InitListHead() {
    LinkNode *node = (LinkNode *)malloc(sizeof(LinkNode));
    node->data = -1;
    node->next = NULL;
    node->prior = NULL;
    return node;
}

/*
 * 判断是否为空
 */
int ListEmpty(LinkedList L) {
    if (L->next == L) {
        return 1;
    }
    return 0;
}

/*
 * 获取长度
 */
int ListLength(LinkedList L) {
    int count = 0;
    LinkedList L2 = L;
    while (L2 != NULL) {
        count++;
        L2 = L2->next;
    }

    return count;
}

/*
 * 获取第i个元素的值,返回的是struct
 */
void GetElem(LinkedList L, int index, LinkNode &e) {
    // 1. 判断索引是否越界
    // 如果索引 = 0,是头地址,没有意义,如果大于Length,没有元素,也没有意义。
    int length = ListLength(L);
    if (index < 0 || index > length) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 2. 循环链表,获取数据
    for (int i = 0; i < index; i++) {
        L = L->next;
    }
    // 3. 此时的L就是我们想要的结点,赋值
    e = *L;
}

/*
 * 返回列表中第1个值与e相同的元素的下标,若不存在返回-1
 */
int LocateElem(LinkedList L, int e) {
    int length = ListLength(L);
    // 1. 判断是否为空
    if (ListEmpty(L)) {
        std::cout << "Get failed. The list is empty." << std::endl;
        return -1;
    }
    LinkedList L2 = L;
    // 2. 循环链表,获取数据
    for (int i = 0; i < length; i++) {
        L2 = L2->next;
        if (L2->data == e) {
            return i + 1;
        }
    }
    // 3. 没找到,返回-1
    return -1;
}

/*
 * 获取前驱
 */
void PriorElem(LinkedList L, LinkNode cur_e, LinkNode &pre_e) {
    // 1. 获取cur_e结点的index
    int index = LocateElem(L, cur_e.data);
    // 2. 如果没找到这个结点,返回错误信息
    if (index == -1) {
        std::cout << "Get failed. current element is not find." << std::endl;
        return;
    }
    // 3. 第一个结点没有前驱结点
    if (index == 1) {
        std::cout << "Get failed. current element is fist of the List." << std::endl;
        return;
    }
    // 4. 通过GetElem获取这个结点的index - 1的节点(即前驱)
    pre_e = *cur_e.prior;
}

/*
 * 获取后继
 */
void NextElem(LinkedList L, LinkNode cur_e, LinkNode &next_e) {
    int length = ListLength(L);
    // 1. 获取cur_e结点的index
    int index = LocateElem(L, cur_e.data);
    // 2. 如果没找到这个结点,返回错误信息
    if (index == -1) {
        std::cout << "Get failed. current element is not find." << std::endl;
        return;
    }
    // 3. 最后一个结点没有后继结点
    if (index == length) {
        std::cout << "Get failed. current element is last of the List." << std::endl;
        return;
    }
    // 4. 通过GetElem获取这个结点的index + 1的节点(即后继)
    next_e = *cur_e.next;
}

/*
 * 在链表的index位置添加结点
 */
void ListInsert(LinkedList L, int index, int e) {
    int length = ListLength(L);
    // 1. 判断index是否合法
    // 如果索引 < 1,是头地址或之前的元素,没有意义,如果大于Length + 1,也没有意义。
    // 当index = 1时为头添加元素,当index=length + 1的时候,为尾添加元素
    if (index < 1 || index > length + 1) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 2. 获取index - 1位置的节点。   a b 两个结点,我们要在b前面添加一个结点,我们需要先获取a结点
    LinkedList L2 = NULL;
    L2 = L;
    for (int i = 0; i < index - 1; i++) {
        L2 = L2->next;
    }
    // 3. 插入结点  a b 两个结点,temp = a,得到a结点就可以得到b结点
    // 创建要插入的结点
    LinkNode *insertElem = InitListHead();
    insertElem->data = e;
    // 将结点插入
    insertElem->next = L2->next;
    insertElem->prior = L2;
    L2->next = insertElem;
    if (insertElem->next != NULL) {
        insertElem->next->prior = insertElem;
    }
}

/*
 * 删除节点
 */
void ListDelete(LinkedList L, int index) {
    int length = ListLength(L);
    // 1. 判断index是否合法
    // 如果索引 < 1,是头地址或之前的元素,没有意义,如果大于Length,也没有意义。 (没有元素)
    if (index < 1 || index > length) {
        std::cout << "Get failed. Index is illegal." << std::endl;
        return;
    }
    // 初始化这个节点
    LinkNode *temp = L;
    for (int i = 0; i < index - 1; i++) {
        temp = temp->next;
    }
    LinkNode *preNode = temp;
    preNode->next = preNode->next->next;
    if (preNode->next != NULL) {
        preNode->next->prior = preNode;
    }

}

/*
 * 对线性表进行遍历
 */
void TraverseList(LinkedList L) {
    // 1. 遍历各个结点,输出data
    // 格式:1 -> 2 -> 3 -> NULL
    int length = ListLength(L);
    for (int i = 1; i < length; i++) {
        L = L->next;
        std::cout << L->data;
        std::cout << " -> ";
    }
    std::cout << "NULL" << std::endl;
}

// 测试函数
int main() {
    LinkedList l1 = InitListHead();
    std::cout << ListEmpty(l1) << std::endl;
    ListInsert(l1, 1, 1);
    TraverseList(l1);
    ListInsert(l1, 2, 2);
    TraverseList(l1);
    ListInsert(l1, 3, 3);
    TraverseList(l1);
    LinkNode l2;
    GetElem(l1,1,l2);
    int s = LocateElem(l1,1);
    LinkNode prior;
    PriorElem(l1,l2,prior);
    LinkNode next;
    NextElem(l1,l2,next);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    ListDelete(l1,1);
    TraverseList(l1);
    return 0;
}

结果:
0
1 -> NULL
1 -> 2 -> NULL
1 -> 2 -> 3 -> NULL
Get failed. current element is fist of the List.
2 -> 3 -> NULL
3 -> NULL
NULL

时间复杂度分析

增:O(n)
要增加一个元素,也需要通过头结点遍历链表找到这个要插入的位置的前驱节点,时间复杂度O(n)

删:O(n)
同样的,删除一个元素,也需要通过头结点遍历链表,找到要删除的元素,然后通过结点指针的转换而删除元素

查:O(n)
需要通过头结点来遍历链表查询

改:O(n)
和查一样,需要先查到这个元素,然后才能更改

虽然链表的时间复杂度都很高,但是它作为一个基础的数据结构仍旧有很高的价值,对我们后面的数据结构学习有很大的影响。
另外链表的好处是它不需要预分配空间,空间不会闲置,或者溢出。


欢迎评论区讨论,或指出问题。 如果觉得写的不错,欢迎点赞,转发,收藏。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jacob_云飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值