与你相识
![](https://img-blog.csdnimg.cn/20210530085239348.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5NTgyNDQz,size_4,color_FFFFFF,t_70,#pic_left)
博主介绍:
– 本人是普通大学生一枚,每天钻研计算机技能,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)
和查一样,需要先查到这个元素,然后才能更改
虽然链表的时间复杂度都很高,但是它作为一个基础的数据结构仍旧有很高的价值,对我们后面的数据结构学习有很大的影响。
另外链表的好处是它不需要预分配空间,空间不会闲置,或者溢出。
欢迎评论区讨论,或指出问题。 如果觉得写的不错,欢迎点赞,转发,收藏。