立刻2021年了线性表你还不知道原理?给老王整的明明白白

以前一直在CSDN发文,忽然在微信发文,好紧张!喜欢能够关注我哦!欢迎点个在看,点个赞,给点鼓励哦。web

1、线性表必知必懂的原理

(一)线性表通俗易懂原理

线性表是n个数据元素的有限序列,最经常使用的是链式表达,一般也叫作线性链表或者链表在链表中存储的数据元素也叫作结点,一个结点存储的就是一条数据记录微信

每一个结点的结构包括两个部分:网络

  • 一、具体的数据值;spa

  • 二、指向下一个结点的指针。.net


在链表的最后一个结点,一般会有个头指针用来指向第一个结点3d



对于链表的最后一个结点,因为在它以后没有下一个结点,所以它的指针是个空指针指针

假如:小明,小张,小李和小郑在排队卖鸡翅,可是排队就是讲究先来先买的原则,不能插队。小明购买鸡翅付钱的时候忽然没钱了,假设小明和小郑认识,小明须要找到小郑借钱来付上买鸡翅的钱。。。那么小明想要找到小郑,就须要先找到他的下一个结点,一看不是小郑,就继续下一个结点,直到找到为止。code


小明是能够找到小郑的,可是小郑就没法找到小明了,也就是说单链表反过来查找是不行的,也被称之为单向链表orm

为了弥补单向链表的不足,咱们能够对单向链表进行改造:对象

对于单向链表,把最后一个元素的指针指向第一个元素,就获得了循环链表

这样小郑就能够查找他本身的next结点,就能够找到小明或者小李等。


因为单向链表一个结点只有指向下一个结点的指针,能够想象一下,是否是也能够修改为每一个结点也指向上一个结点,是否是就能够找到本身上一个结点的数据了呢。

咱们再增长一个指向上一个结点的指针,这样就获得了双向链表



固然了,还有更好的办法,那就是把循环链表双向链表进行结合就获得了双向循环链表



不论是循环链表仍是双向链表,仍是双向循环链表,都是在单向链表的基础上加以改造获得的,改造后的链表在操做某种数据的时候能够提升必定的效率,因此单向链表是基础。

2、线性表对数据的操做

对数据的操做无非就是对数据的增删改查。只是不一样的结构有着不一样的处理逻辑罢了。

(一)增长操做(老王插队神操做)

小明、小张、小李、小郑在排着队取票,忽然来了一个老王,老王很是的着急,由于老王立刻就要到火车发车的时间了,只好插队了,此时老王跟后面全部的排队的人都打了个招呼,而后你们也都赞成他插队进去,那么老王就先去取票了,咱们忽略打招呼的过程,重点放在如何插队


咱们先无论如何插入到链表中的,先看图说话

老王若是想插队一定插入到小明的后面,由于老王在插队的过程当中小明此时可能会正在取票呢。

那么插入老王后的数据就是:


整个插入操做也很是的简单,只须要让老王的next指向小张,而后小明再指向老王就ok了。


思考一下????

反过来操做能够吗?

小明先指向老王老王的next指向小张

能够吗?

答案是不能够的,这样的话,小明先指向老王以后,小张以及小张以后的数据会所有丢失的。不信你看:



代码以下:

1newNode.next = head.next
2head.next = newNode

(二)删除操做(小明取完票让位给老王)

老王要想取到票,还欠一点火候,欠什么呢?须要等待小明取完票,而后离开才能够的。

那么就须要小明离开这个链表,咱们一般说删除小明这个结点。


删除操做也比较简单,只须要把前一个结点指向后面的后面的这个结点就ok了。

代码:(直接就能够忽略小明这个结点)

1head.next=head.next.next;

(三)查找操做

查找操做咱们一般会查两种,第一种是按照位置的序号,第二种是按照值来查找。

例如:

  • 查找第3个位置的是谁;

  • 查找小张是否还在排队。

在链表中的查找功能是比较弱的,对于链表中的查找,惟一的办法就是一个挨着一个的遍历去对比,对比较着去查找。

时间复杂度也就是O(N)。

3、单链表案例

(一)案例1:反转链表

一、题目描述

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

来源:力扣(LeetCode)
连接:https://leetcode-cn.com/problems/reverse-linked-list
著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。


二、解题思路









三、解题代码

 1/**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 *     int val;
5 *     ListNode next;
6 *     ListNode(int x) { val = x; }
7 * }
8 */

9class Solution {
10    public ListNode reverseList(ListNode head) {
11
12        if(head==null)
13            return head;
14
15        //定义三个指针暂存后面的或者前面的结点,防止丢失。
16        ListNode curr,prev,next;
17        curr=head;
18        prev=next=null;
19
20        while(curr!=null){
21            next = curr.next;
22            curr.next = prev;
23            prev=curr;
24            curr=next;
25        }
26
27        return prev;       
28    }
29}

若是不明白,能够本身画图来试试。

(二)案例2:找出链表的中间节点

一、题目描述

876. 链表的中间结点

难度简单256收藏分享切换为英文关注反馈

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

若是有两个中间结点,则返回第二个中间结点。

示例 1:

1输入:[1,2,3,4,5]
2输出:此列表中的结点 3 (序列化形式:[3,4,5])
3返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
4注意,咱们返回了一个 ListNode 类型的对象 ans,这样:
5ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

示例 2:

1输入:[1,2,3,4,5,6]
2输出:此列表中的结点 4 (序列化形式:[4,5,6])
3因为该列表有两个中间结点,值分别为 3 和 4,咱们返回第二个结点。

提示:

  • 给定链表的结点数介于 1100 之间。

https://leetcode-cn.com/problems/middle-of-the-linked-list/



二、解题思路

思路很简单,就是利用两个指针来完成,一个走的比较快的,一个走的比较慢的。

每次快的走2个(next.next),每次慢的走1个节点(next)。

当快等于null时(next.next=null时),中止;

当快的next不为空时,返回慢的next节点。

当快的next为空时,返回慢的当前节点。



三、解题代码

 1 //找出链表中间节点
2    static public ListNode middleNode(ListNode head) {
3
4        if(head==null)
5            return head;
6        ListNode fast,//快
7                slow;//慢
8        fast=slow=head;
9
10        while (fast!=null && fast.next!=null && fast.next.next!=null){
11            fast = fast.next.next;
12            slow = slow.next;
13        }
14
15        if(fast.next!=null)
16            return slow.next;
17
18        return slow;
19    }

(三)案例3:判断链表是否有环

一、题目描述

141. 环形链表

难度简单738收藏分享切换为英文关注反馈

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,咱们使用整数 pos 来表示链表尾链接到链表中的位置(索引从 0 开始)。若是 pos-1,则在该链表中没有环。

示例 1:

1输入:head = [3,2,0,-4], pos = 1
2输出:true
3解释:链表中有一个环,其尾部链接到第二个节点。


示例 2:

1输入:head = [1,2], pos = 0
2输出:true
3解释:链表中有一个环,其尾部链接到第一个节点。


示例 3:

1输入:head = [1], pos = -1
2输出:false
3解释:链表中没有环。


进阶:

你能用 O(1)(即,常量)内存解决此问题吗?



二、解题思路

此题也是能够利用快慢指针来完成的,一样,快指针一次走两步,慢指针一次走一步,若是有环的话,快和慢两个指针迟早会相遇的。那么若是快指针的val等于慢指针的val那么直接返回true便可。

三、解题代码

 1/**
2 * Definition for singly-linked list.
3 * class ListNode {
4 *     int val;
5 *     ListNode next;
6 *     ListNode(int x) {
7 *         val = x;
8 *         next = null;
9 *     }
10 * }
11 */

12public class Solution {
13    public boolean hasCycle(ListNode head) {
14         if(head==null)
15            return false;
16
17        ListNode fast,slow;
18        fast=slow=head;
19        while (fast!=null && fast.next!=null && fast.next.next!=null){
20            fast=fast.next.next;
21            slow=slow.next;
22            if(fast.val==slow.val)
23                return true;
24        }
25
26        return false;
27    }
28}

4、链表总结

链表对数据的存储方式是按照顺序的存储。


何时用?

  • 当数据元素不肯定时。

  • 当须要常常进行数据的新增和删除时。

链表的反转、快慢指针是高效的操做链表的主要方法,是必需要掌握的内容。







本文分享自微信公众号 - TrueDei(monkeystudy)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索