单链表

作者: Cracks_Yi | 来源:发表于2017-07-26 18:51 被阅读0次

单链表由一个个节点(Node)组成,引用LeetCode里对单链表节点的表示:
<pre>
/**

  • Definition for singly-linked list.
  • class ListNode {
  • int val;
  • ListNode next;
  • ListNode(int x) {
  •    val = x;
    
  •    next = null;
    
  • }
  • }
    */
    </pre>

每个节点里包含储存的内容及下一个节点的引用,这样,获得一个头结点(head),就可以对其他任意节点进行操作。



以下是一些单链表经典题,LeetCode上都有。

1.判断是否有环

可以用哈希表(HashSet)通过判重的方式解决,也可以用一快一慢两个指针来解决,这样空间复杂度只有O(1)。具体思想是,快指针每次移动2,慢指针每次移动1,如果有环,那么快指针在某个时刻会追赶上慢指针。注意初始化时要让快指针先移一格,否则最开始快慢指针就会重合。
<pre>
public boolean hasCycle(ListNode head) {

    if(head == null) return false;
    
    ListNode fast = head;
    ListNode slow = head;
    
    while(fast != null && fast.next != null){
        slow = slow.next;
        fast = fast.next.next;
        if(fast == slow) return true;
    }
    
    return false;
      
}</pre>

那么环从哪里开始呢?假设慢指针从头结点到环起始处需要走A步,再走B步与快指针相遇。此时快指针走了2A+2B比慢指针多走一圈N,2A + 2B = N + A + B。
由此得出 N = A + B。
慢指针已经走了一圈中的B,再走A步又回到环起始处,而A正是从头结点到环起始处的步数,用另一个指针从头结点开始与慢指针同步走,相遇处即为环起始处。
<pre>

public ListNode detectCycle(ListNode head) {
    
    if(head == null) return null;
    
    ListNode slow = head;
    ListNode fast = head;
    
    while(fast != null && fast.next != null){
        slow = slow.next;
        fast = fast.next.next;
        
        if(slow == fast){
            ListNode start = head;
            while(start != slow){
                start = start.next;
                slow = slow.next;
            }
            return start;
        }
    }
    
    return null;
    
}

</pre>

</br>

2.反转链表

设置前后两个指针,每次让后指针的next指向前指针,然后两个指针都往后挪一位。注意前指针应初始化为null,应设置一个临时变量储存后指针的后一位以支持挪动。
<pre>
public ListNode reverseList(ListNode head) {

    ListNode pre = null;
    ListNode curr = head;
     
    while(curr != null){
        ListNode next = curr.next;
        curr.next = pre;
        pre = curr;
        curr = next;
    }
    
    return pre;
}

</pre>

</br>

3.合并两个有序单链表

实现思想就是用small,big两个指针来分别指向两个链表中当前节点值较小和较大的,如果small的下一个节点比big大了,就把small的next指向big,然后big指向原先的small链表元素。
<pre>
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {

    if(l1 == null) return l2;
    if(l2 == null) return l1;
    
    ListNode small = null;
    ListNode big = null;
    
    if(l1.val > l2.val){
        small = l2;
        big = l1;
    }else{
        small = l1;
        big = l2;
    }
    
    ListNode head = small;
    
    while(small.next != null && big != null){
        if(small.next.val > big.val){
            ListNode temp = small.next;
            small.next = big;
            small = big;
            big = temp;
        }else{
            small = small.next;
        }
        
    }
    
    small.next = big;
    
    return head;        
    
}

</pre>
看了下LeetCode其他人答案发现还可以递归解决,于是顺手也写了个,确实简洁不少。
<pre>
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null) return l2;
if(l2 == null) return l1;

    ListNode head = null;
    
    if(l1.val < l2.val){
        head = l1;
        head.next = mergeTwoLists(l1.next,l2);
    }else{
        head = l2;
        head.next = mergeTwoLists(l1,l2.next);
    }
    
    return head;   
}

</pre>

相关文章

  • 单链表 C++

    单链表 C++ 题目 1、创建单链表2、初始化单链表3、释放单链表4、获取单链表中元素的数量5、输出单链表中的所有...

  • 线性表:顺序表和链表

    顺序表(数组)优缺点 链表优点 单链表使用 单链表结构 单链表初始化 单链表初始化 单链表建立: 头插法 尾插法 ...

  • 单向链表算法

    单向链表 反转单向链表 单链表查找倒数第k个节点 单链表递归倒序打印 单链表排序 单链表删除重复节点

  • 链表基本操作

    1、删除单链表节点 2、插入单链表结点 单链表具体实现

  • 25_静态单链表的实现

    关键词: 单链表的一个缺点、静态单链表设计思路、静态单链表的继承层次结构、静态单链表的实现思路、静态单链表的实现 ...

  • 线性表的链式存储-单链表

    单链表操作 [x] 单链表的创建(尾插法、头插法) [x] 单链表的查找操作 [x] 单链表的删除操作 [x] 单...

  • Algorithm小白入门 -- 单链表

    单链表递归反转链表k个一组反转链表回文链表 1. 递归反转链表 单链表节点的结构如下: 1.1 递归反转整个单链表...

  • 单链表反转

    单链表 单链表反转 递归方法

  • JavaScript数据结构2——单链表

    以下的代码包括了以下几部分 单链表初始化 单链表的插入 单链表的删除 单链表的创建(头插法) 单链表的创建(尾插法...

  • 链表

    链表:通过“指针”将零散的内存块联系起来。常见链表结构:单链表、循环链表和双链表。 单链表 对比数组学习单链表 循...

网友评论

      本文标题:单链表

      本文链接:https://www.haomeiwen.com/subject/xvxjkxtx.html