链表

一、概述

 线性表是最常用的也是最简单的一种数据结构,而线性表又分为顺序表和链表,顺序表就是Java中的ArrayList集合了,而链表则是对应的是LinkedList。相对来说,线性表的随机访问速度较快,而链表必须要从头节点开始查找;链表的优势在于插入和删除的复杂度较低,时间复杂度为O(n)。一个单链表的示意图如下:

https://www.cnblogs.com/skywang12345/p/3561803.html

一个简单Java单链表的成员域如下:

    /* Domain */
    private int size;
    Node Head;

    /* Node Definition */
    class Node <T>
    {
        T val;
        Node<T> next;
        Node(T x) { val = x; }
    }

务必谨记节点成员类与链表类的关系。

除单链表外,双向链表也是很常用的一种链表,双链表不仅可以指向后继,还将指向前驱节点,将访问前驱节点的时间复杂度从O(n)将为O(1),性能更加优异,相应的实现也会更加复杂一些,需增加前驱指针。

事实上,还有一种链表不被经常使用,这里做简单介绍——循环链表(circular linked list),特点是最后一个节点的指针指向头节点,这样,单链表也能通过任一节点找到其他所有节点。基本操作和单链表相同,只是遍历时将判空改为判断是否等于头节点。如果将双向链表和循环链表结合一起就产生了循环双向链表或者叫双向循环链表。这样从链表中的一个节点访问另一个节点效率将会十分之高。

注意:一般大家所说的双向链表均为本文中的循环双向链表,我在此引入这些概念只是为了更好的解释和介绍。

 

    /* Domain */
    private int size;
    Node Head;
Node Tail; /* Node Definition */ class Node <T> { T val; Node<T> next;
Node<T> prior; Node(T x) { val = x; } }

二、链表实现

class List <T>
{
    /* Domain */
    private int size;
    Node Head;

    /* Node Definition */
    class Node <T>
    {
        T val;
        Node<T> next;
        Node(T x) { val = x; }
    }

    /* Constructor */
    public List()
    {
        size = 0;
        Head = null;
    }

    /* Function */
    public int len()
    {
        return size;
    }

    public void add (T v, int i)
    {
        Node <T> N = new Node (v);
        if (i > size || i < 0)
        {
            System.out.print("Out of length");
        }
        else if (i == 0)
        {
            Head = N;
            size++;

        }

        else
        {
            int m=1;
            Node p = Head;
            while(m < i)
            {
                p = p.next;
                m++;
            }
            N.next = p.next;
            p.next = N;
            size++;

        }
    }

    public void delete (int j)
    {
        if (j > size || j <= 0)
        {
            System.out.print("Out of length");
        }

        else if (j == 1)
        {
            Head = Head.next;
        }
        else
        {
            int m=1;
            Node p = Head;
            while(m < j - 1)
            {
                p = p.next;
                m++;
            }

            p.next = p.next.next;
            size--;

        }

    }
    public void print()
    {
        System.out.print("Head->");
        Node q = Head;
        while (q!=null)
        {
            System.out.print(q.val+"->");
            q=q.next;
        }
        System.out.print("Tail\n");

    }

}
SingleList 

测试小case代码:

    public static void main(String [] args)
    {
        List <Integer> l = new List();

        for (int i = 0; i < 5; i++)
            l.add(i+1,l.len());
        l.print();
        System.out.print(l.len()+"\n");

        l.delete(4);
        l.print();
        System.out.print(l.len()+"\n");

        l.delete(2);
        l.print();
        System.out.print(l.len()+"\n");

    }
View Code

结果:

Head->1->2->3->4->5->Tail
5
Head->1->2->3->5->Tail
4
Head->1->3->5->Tail
3

 

核心操作: 

在节点p后添加节点q:

q.next=p.next;

p.next=q;

删除节点p后面的节点:

p.next=p.next.next;

 

双链表的核心操作:

在节点p添加节点q:

q.next=p.next;

p.next.prior=q;

p.next=q;

q.prior=p;(顺序不能随意哦)

在节点p添加节点q: 

q.prior=p.prior;

p.prior.next=q;

p.prior=q;

q.next=p;

删除节点p

p.prior.next=p.next;

p.next.prior=p.prior;

 

无需死记硬背,找出规律便得心应手! 

 

 三、实战

Remove Nth Node From End of List

 

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

 

 本题为LeetCode第19题,给定一个链表一个整数n(有效的,不会超过链表长度等),删除倒数第n个节点,然后返回删除后的链表头。
要求:一次循环。
 
这题我第一想法就是先转换为Java的LinkedList集合,然后用丰富的API解题,但是提交之后总是会出现ConCurrentXXX的异常。所以还是踏踏实实的按链表的方法来,最终还是靠着百度的灵感解了题,看了别人的解析的前半部分写出了代码{😅}。
 
主要思路是,从头开始,向后走n个节点,判断是否到头,到头意味着删除的是第一个节点,那就直接返回head.next即可;如果没有到头,那就设置两个指标,一个在当前位置,另一个从头开始,然后共同向后,直到后面到结尾,前面的到达的位置就是要删除的节点位置。
class ListNode {
      int val;
      ListNode next;
      ListNode(int x) { val = x; }
  }

public class LinkList {
     ListNode removeNthFromEnd(ListNode head, int n) {

        if(head.next == null)
        {
            return null;
        }

        ListNode q=head;
        ListNode p=q;
        for(int i =1; i<n;i++)
        {
            p=p.next;
        }
        if(p.next == null)
        {
            return head.next;
        }

        else
        {

            for( ; p.next.next!=null;p=p.next)
                q=q.next;
        }
        if(q.next.next == null)
        {
            q.next = null;
            return head;
        }
        else {
            q.next = q.next.next;
            return head;
        }

    }
}

不要忘了判断是不是只有一个节点的情况,就因为这个我多提交了一次

 

posted @ 2019-07-07 22:15  LeftBody  阅读(164)  评论(0编辑  收藏  举报