数据结构与算法之链表

链表的分类:

(1)单链表

头插法:只需要维护一个头结点即可,常用来模拟堆栈;

尾插法:需要维护头结点和尾结点,常用来模拟队列。

(2)双向链表

双向遍历,可以用来保存网页的历史记录等;

(3)循环链表

经常出现在面试题中,判断链表是否有环。

链表的删除

方式一:维护两个指针,current(表示当前节点)和previous(表示当前节点的前一个节点)。当current遍历到要删除的元素时,执行previous->next = current->next,并删除current。在删除时,需要判断current是否等于head节点。

方式二:维护一个二级指针,Node ** current和一个临时变量entry。删除时只需要执行*current = entry -> next. 并删除entry即可,无需判断是否为head节点。

基于内存池的链表

传统链表的缺点:链表在插入过程中会调用系统函数分配内存,然后将该块内存链接到链表中。插入操作有三个缺点:

(1)进行频繁的系统调用,会浪费不少时间;

(2)在链表节点分配释放的过程中会产生很多内存碎片,不利于分配整块内存;

(3)可能会导致频繁的cache缺失;

解决方案:

构造一个内存池,每次插入都从内存池中获取一个节点,每次删除都将节点放回内存池。这样做的优点是不存在内存碎片,也不进行系统调用。

链表的反转(面试常考)

(1)思路一:在从前往后遍历的过程中进行反转。维护三个指针,分别指向当前节点以及当前节点的前后节点。

(2)思路二:将第三个节点到第N个节点,依次逐节点插入到第一个节点(head节点)之后,最后将第一个节点挪到新表的表尾。

(3)思路三:递归的处理head后面的节点,然后再修改head和head后面节点的指向。

倒序打印链表

(1)递归:倒序打印意味着先最后的元素,然后依次往前打印,可以用递归实现这个过程。递归的打印head后面所有的节点,然后打印head节点。

(2)栈模拟:递归使用系统栈(活动记录),我们可以用STL中的栈来模拟上述递归过程。首先顺序遍历一遍链表,将元素放入堆栈,然后依次出栈打印元素。

判断链表是否有环

(1)如何判断是否存在环?

解法:设置一对快慢指针,同时从链表的头开始往前遍历。慢指针一次前进一步,快指针一次前进两步,如果有环则两个指针会相遇。

(2)如何知道环的长度?

解法:记录下问题(1)的碰撞点,快慢指针再从该位置遍历一遍环。下次碰撞慢指针走过的距离就是环的长度。

(3)如何找出环的连接点在哪里?

解法:碰撞点到连接点的距离 = 头指针到连接点的距离,再次从两点遍历即可。

(4)带环链表的长度是多少?

解法:问题2+问题3.

间接寻址的基本概念

间接寻址简单描述就是二级指针的应用。二级指针有三个含义:指向指针的指针、一维数组、二维数组。间接寻址在此特指其一维数组的含义。

间接寻址是数组和链表的组合。既保留了数组的许多优点,又获得了链表的重要特色。首先,可以根据索引在O(1)的时间内访问每个元素。其次,可以采用二分在对数时间内对一个有序表进行搜索。最后,在诸如插入和删除操作期间不必对元素进行实际的移动。间接寻址使用指针数组来跟踪每一个元素,对元素本身如何分配不设限制(可离散可连续)。

间接寻址的应用

(1)内存池

自构建等块内存池,每一个指针分别指向每一块内存的首地址。内存池可以避免内存碎片和系统调用。

(2)散列链表

如果指针指向的元素包含next指针,则间接寻址变成了散列链表。

模拟指针的基本概念

模拟指针简单描述就是利用数组的下标当指针。模拟指针的最大用途是解决并查集问题。

(1)实现一:首先构造一个节点数组,节点包含两个域:data和link。link域指向数组中的其他节点。和间接寻址有相似之处。

(2)实现二:数组只包含link域,可以用来模拟树。

等价类的定义

定义:假定有一个具有n个元素的集合U,另有一个具有r个关系的集合R。如果(a,b)属于R,则元素a和b是等价的。等价类是指相互等价元素的最大集合。换句话说,将集合U根据关系进行划分,类内的元素等价,可以看做是一种聚类。

离线等价类:已知n和R,确定所有的等价类。

在线等价类:初始时有n个元素,每个元素都属于一个独立的等价类。然后不停的执行Find和Union操作向R中添加新关系。通常被称为并查集问题。

并查集的基本概念

并查集的操作:

(1)Find:查询元素a和b是否属于同一类;

(2)Union:合并元素a和b所在的类。

并查集的实现:

采用方式二的模拟指针。数组的下标即表示指针,指针的指向使并查集构成了一棵虚拟的森林。但是并查集不关注每棵树的形状以及相互指向关系,只关注最终的根节点以及该树的元素个数或者高度。

并查集的优化:

可以根据重量规则或者高度规则对并查集的操作进行优化。

时间: 2024-10-23 00:50:03

数据结构与算法之链表的相关文章

Java数据结构和算法之链表

三.链表 链结点 在链表中,每个数据项都被包含在'点"中,一个点是某个类的对象,这个类可认叫做LINK.因为一个链表中有许多类似的链结点,所以有必要用一个不同于链表的类来表达链结点.每个LINK对象中都包含一个对下一个点引用的字段(通常叫做next)但是本身的对象中有一个字段指向对第一个链结点的引用. 单链表 用一组地址任意的存储单元存放线性表中的数据元素. 以元素(数据元素的映象)  + 指针(指示后继元素存储位置)  = 结点(表示数据元素 或 数据元素的映象) 以"结点的序列&q

数据结构与算法-单向链表

概述 由于最近在工作中需要用到树形结构来解决一些问题,所以萌生了系统学习“数据结构和算法”的想法,于是乎从最简单的表结构开始.由于数组是最简单的表结构的实现,也是各个编程语言内置的数据类型,所以不做更多的记录.表结构中以下实现打算学习: LinkedList Stack Queue HashTable Dictionary 本篇为学习数据结构的第一篇随笔,从最简单的单向链表开始吧. 实现(C#) 平台:dotNet Core 1.0, C# IDE:VSCode 如果考虑算法复用的话,可以实现泛

数据结构与算法(三)--链表

一.链表 单项链表.循环链表.双向链表 链表和数组不同,链表的每个元素都存储了下一个元素的地址,所以链表不需要连续的存储空间: 如果我们申请一个 100MB 大小的数组,当内存中没有连续的.足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败. 1.单链表:内存块称为链表的"结点",把这个记录下个结点地址的指针叫作后继指针 next 头结点用来记录链表的基地址.有了它,我们就可以遍历得到整条链表.而尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址

数据结构与算法三(链表)

一.链表 1.什么是链表 和数组一样,链表也是一种线性表 从内存结构上看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构 链表中的每一个内存块被称为节点Node,节点除了存储数据外,还需记录链上下一个节点的地址,即后继指针next 2.常见的缓存策略 先进先出策略FIFO (First In,First Out) 最少使用策略LFU (Least Frequently Used) 最近最小使用策略LRU(Least Recently Used) 3.常

数据结构和算法--3链表(单向链表、双向链表、环形单向链表和约瑟夫问题)

链表 链表是以节点的方式来存储 每个节点包含data域和next域,指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定 单向列表 最大特点是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能. 单链表分为两种:有头链表和无头链表. 有头节点的增删改查 定义一个单链表的类: //定义一个SingleLinkedList,单链表,管理HeroNode class SingleLinkedList{ //初始

研磨数据结构与算法-04链表

一,链表的节点 /* * 链结点,相当于是车厢 */ public class Node { //数据域 public long data; //指针域 public Node next; public Node(long value) { this.data = value; } /** * 显示方法 */ public void display() { System.out.print(data + " "); } } 二,简单链表 /* * 链表,相当于火车 */ public

数据结构和算法-008 链表

链表,要简单讲一讲. 链(Link)一般有两个部分,一是节点(node)和指针(point) Node:存放内容(content) Point:指向下一个节点,把节点穿起来,就形成链表 看代码, 这个的link其实是一个节点(Node),link穿起来就是一张链表(LinkedList) 实现一下功能 创建链表 在链表头部添加一个节点 删除头部节点 查找一个节点 删除指点节点 public class Link {          public String bookName;     pub

数据结构与算法—单链表

By francis_hao    Dec 24,2016 本文由 刘英皓 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可.欢迎转载,请注明出处:转载自:http://www.cnblogs.com/yinghao1991/ 参考

数据结构与算法 —— 单向链表的逆转

1 List Reverse(List L) 2 { 3 Node *new_head, *old_head, temp; 4 new_head = NULL; 5 old_head = L; 6 while(old_head) 7 { 8 temp = old_head->next; 9 old_head->next = new_head; 10 new_head = old_head; 11 old_head = temp; 12 } 13 14 L = new_head; 15 retu