链表
链表是线性表的链式存储结构,是用一组任意的存储单元来存储数据,存储单元不一定是连续的。数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构。
链表的每个元素称为一个节点,每个节点都可以存储在内存中的不同的位置,为了表示每个元素与后继元素的逻辑关系,以便构成“一个节点链着一个节点”的链式存储结构,
链表的节点
每个节点都包含两部分,第一部分称为链表的数据区域,用于存储元素本身的数据信息,它不局限于一个成员数据,也可是多个成员数据。第二部分是一个结构体指针,称为链表的指针域,用于存储其直接后继的节点信息,这里用next表示,
next的值实际上就是下一个节点的地址,当前节点为末节点时,next的值设为空指针
1. data: 数据元素本身,其所在的区域称为数据域;value代表该节点存储的值
2. next: 指向直接后继元素的指针,所在的区域称为指针域;
next指向下一个节点,next可能指向一个单一节点,也可能指向一个链表,也可能指向null(代表尾节点)。
头指针就是链表的名字,仅仅是个指针而已。头结点是为了操作的统一与方便而设立的,放在第一个有效元素结点(首元结点)之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。
双向链表
双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
数组
1. 数组可以方便的遍历查找需要的数据。
2. 在查询数组指定位置(如查询数组中的第4个数据)的操作中,只需要进行1次操作即可,时间复杂度为O(1)。
3. 数组在内存中占用了连续的空间,在进行类似的查找或者遍历时,本质是指针在内存中的定向偏移。然而,当需要对数组成员进行添加和删除的操作时,数组内完成这类操作的时间复杂度则变成了O(n)。
链表进行插入和删除操作上比数组更加高效,链表操作的时间复杂度仅为O(1)。
链表在内存中不是连续存储的,所以可以充分利用内存中的碎片空间。
链表是很多算法的基础,最常见的哈希表就是基于链表来实现的。
在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的,动态内存的生存期有程序员自己来决定,使用非常灵活,但也易出现内存泄漏的问题,
为了防止内存泄漏的发生,必须及时调用free()释放已不再使用的内存。
链表存放在堆里。
问题一: 查找两个链表的公共节点的几种实现方案
公共节点:两个链表拥有公共节点不是指两个链表的节点的数据域相同,而是指两个链表的指针指向同一个节点,即具有相同的地址。
由于单链表只有一个next域,所以只要找到两个链表的第一个公共节点,那么从第一个公共节点开始,两个链表的公共节点节点的next 指向是一致的。这个节点后面的节点均是重合的,有部分重合的单链表,拓扑形状看起来像Y。
参考:两个链表的第一个公共节点, Masonry寻找2个view的公共父视图_gcs的博客-CSDN博客
问题二: 判断链表是否有环?
1. 判断链表是否存在环,有环的话就没有尾结点,不存在一个结点的next指针是null。链表如果很长,较为复杂。
或者: 把所有节点的next指针地址存起来,如果有节点的next 指向相同就有环。
2. 利用快慢指针
定义两个指针,初始位置都放在头节点,快慢指针一起走,快指针一次走两步(需要注意边界条件),慢指针一次走一步,如果快指针走到末节点NULL,该链表就不带环。如果快慢指针相遇,该链表就带环。
问题三: 链表逆序翻转
1. 三个指针法
2. 创建新表,头插法
3. 递归后移法
链表反转步骤分解附图_Pichairen-CSDN博客 图文讲解较为详细怎么一步一步替换,三个指针法,能看到明白
数据结构中-实现单链表的反转_伍华锋的博客-CSDN博客_数据结构单链表反转
单向链表逆序_潇洒的程序员-CSDN博客 三个指针的方法具体代码实现
参考:
什么是单链表,链式存储结构详解
通俗易懂讲解 链表 - 知乎
链表(单向链表的建立、删除、插入、打印) - 蓝海人 - 博客园 有链表的内存申请和销毁讲解
链表基础知识总结_u012531536的专栏-CSDN博客_链表
环形链表专题_渣渣-CSDN博客_环形链表 链表带环的判断
数组和链表的区别_博可睿的博客-CSDN博客_数组和链表的区别 数组和链表的区别