数据结构之单链表

什么是单链表

单链表线性链式存储结构 ,每个节点存数据下一个节点地址,节点不连续分布在内存。

单链表的结构

我们要先来构建结点的结构

节点分为数据域和指针域

数据域用来储存数据,指针域用来寻找下一个节点的位置

cpp 复制代码
typedef int LDataType;
typedef struct ListNode {
    LDataType data;         // 存储数据
    struct ListNode* next;  // 存放后继结点地址
}LNode, * LinkList;

初始化单链表

我们构建的链表是有哨兵位头节点的链表,初始化也就是将哨兵位头节点初始化,由于哨兵位节点并不用来储存数据,我们将其搞成-1.

链表节点的数量是不确定的,我们需要malloc来申请空间,然后我们将新建节点的操作单拎出来来实现,方便之后的使用

cpp 复制代码
// 创建一个新结点
LNode* BuyListNode(int data)
{
	LNode* newNode = (LNode*)malloc(sizeof(LNode));
	if (newNode == NULL)
	{
		printf("申请空间失败\n");
		return  NULL;

	}
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}


// 初始化链表
LNode* ListInit()
{
	LNode* head = BuyListNode(-1);
	return head;
}

插入数据

我们观察上面的图片,我们在插入时要记录插入位置的前面一个节点,然后new一个新的节点.

prev,new,next

这个时候我们由两种方式来解决,第一种就是将前面节点记录,将后面节点记录,然后在按照顺序对其进行连接

第二种就是不新起节点,但是这时必须要遵循操作的顺序,不然链表就断链了

先将new的next指向prev的next,再将prev的next指向new.

主要的操作就是这样,但真的实践起来我们还要考虑头插,尾插是否可以实现

边界的处理,要查看能不能实现头插,尾插这样的操作

cpp 复制代码
void ListInsert(LNode* L, int i, LDataType x)
{
	assert(L);
	assert(i >= 0);
	//先new一个新的节点出来
	LNode* cur = BuyListNode(x);
	LNode* prev = L;
	int count = -1;
	
	while (prev&&count<i-1)
	{
		prev = prev->next;
		count++;
	}
	
	if (prev == NULL || count != i - 1)
	{
		free(cur);
		return;
	}

	// prev   cur   next
	LNode* next = prev->next;
	prev->next = cur;
	cur->next = next;


}

删除数据

删除的逻辑

第一步也是要记录删除节点的前面一个位置的节点

后面也可以和插入哪里类似,这里不做过多的赘述,但是要注意删除的节点要free

主要的操作就是这样,但真的实践起来我们还要考虑头插,尾插是否可以实现

边界的处理

cpp 复制代码
// 删除链表中下标为i的结点,并用x带出结点的值
LDataType ListDelete(LNode* L, int i)
{
	//先找出删除位置的前一个位置
	assert(L);
	assert(i >= 0);
	LNode* prev = L;
	int count = -1;

	while (prev && count < i - 1)
	{
		prev = prev->next;
		count++;
	}

	if (prev == NULL || count != i - 1)
	{
		return;
	}
	//prev  cur  next
	LNode* next = prev->next->next;
	LNode* cur = prev->next;
	LDataType x = cur->data;
	prev->next = next;
	free(cur);
	return x;
}

销毁单链表

就是将整张表遍历一遍,并且删除节点,为了防止找不到下一个节点我们要记录下一个节点

cpp 复制代码
// 销毁链表
void ListDestroy(LNode* L)
{
	LNode* cur = L;

	while (cur)
	{
		LNode* next = cur->next;
		free(cur);
		cur = next;
	}
}

头删尾删,头插尾插,判空

比较简单,这里不多做赘述

cpp 复制代码
bool ListEmpty(LNode* L)
{
    assert(L);
    return L->next == NULL;
}

void ListPushFront(LNode* L, LDataType x)
{
    assert(L);
    LNode* newNode = BuyListNode(x);
    newNode->next = L->next;
    L->next = newNode;
}

void ListPushBack(LNode* L, LDataType x)
{
    assert(L);
    LNode* tail = L;
    while (tail->next)
    {
        tail = tail->next;
    }
    tail->next = BuyListNode(x);
}

LDataType ListPopFront(LNode* L)
{
    assert(L);
    assert(!ListEmpty(L));
    LNode* del = L->next;
    LDataType x = del->data;
    L->next = del->next;
    free(del);
    return x;
}

LDataType ListPopBack(LNode* L)
{
    assert(L);
    assert(!ListEmpty(L));
    LNode* prev = L;
    while (prev->next && prev->next->next)
    {
        prev = prev->next;
    }
    LNode* del = prev->next;
    LDataType x = del->data;
    prev->next = NULL;
    free(del);
    return x;
}

单链表与顺序表的对比

操作 顺序表 单链表
随机访问(下标取值 arr i O(1) 直接寻址 O(n) 必须从头遍历
头部插入 / 删除 O(n)(全体数据后移 / 前移) O(1)(头插只需改头指针)
尾部插入 / 删除(未满) O(1) O(n)(需要遍历找尾)
中间第 i 位插删 O(n)(大量搬数据) O(n)(找前驱,找到后修改指针O(1))
按值查找 无序O(n) 只能遍历O(n)
存储空间
  • 顺序表 :连续堆内存,预先分配容量,存在闲置空间浪费;存数据 + 无额外开销。
  • 单链表 :节点离散分布,按需malloc;每个节点多存 1 个next指针,额外空间开销大
扩容逻辑
  • 顺序表:空间满要重新开辟更大数组 + 拷贝全部元素,扩容代价高。
  • 链表:不用整体扩容,新增结点单独申请内存,无整体搬迁。
随机存取
  • 顺序表:依靠首地址 + 偏移量,支持[下标]随机访问。
  • 链表:无连续地址,不支持随机访问,想找第 i 个必须从头挨个走
增删本质区别
  • 顺序表:改位置 =移动大量元素(数据搬家)。
  • 单链表:找到前驱后 =修改 2 处指针指向,数据不移动。

顺序表适合,频繁的查询,在尾部插入和删除较多,随机访问较多的场景

单链表适合,频繁的头尾插入,删除.

相关推荐
And_Ii1 小时前
LeetCode 1. 两数之和 python
数据结构·算法·leetcode
cpp_25011 小时前
P10377 [GESP202403 六级] 好斗的牛
数据结构·c++·算法·题解·洛谷·gesp六级
邪修king1 小时前
C++ 红黑树自平衡核心:旋转变色、规则详解与 STL 选型逻辑
数据结构·c++·b树·算法
CS创新实验室13 小时前
从顺序表到动态数组:数据结构的永恒基石与现代语言的优雅封装
数据结构·算法
8Qi814 小时前
LeetCode 23. 合并 K 个升序链表 —— 小顶堆(PriorityQueue)
数据结构·算法·leetcode·链表·
QiLinkOS15 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
Boom_Shu17 小时前
长方形的关系
数据结构·c++·算法
Lsk_Smion18 小时前
力扣实训 _ [543].二叉树的直径 _ [23].合并K个升序列表
数据结构·算法·leetcode
ID_1800790547320 小时前
淘宝商品详情数据接口深度解析:架构、鉴权、数据结构与实战
数据结构·架构