LinkedList与链表

链表

链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUdImA8F-1647616558482)(D:\Typora笔记\图片\image-20220313165113953.png)]

注意:

​ 1. 从上图可看出,链式结构在逻辑上连续的,但在物理上不一定连续

  1. 现实中的结点一般都是在堆上申请出来的

  2. 从堆上申请的空间,是按照一定策略来分配的,两次申请的空间可能连续可能不连续

而链表的结构非常的多样:

1.单向 或 双向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QNx1UFEN-1647616558484)(D:\Typora笔记\图片\image-20220313165635625.png)]

2.带头或 不带头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4nkrSMm-1647616558485)(D:\Typora笔记\图片\image-20220313165658050.png)]

3.循环或非循环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ePJd2jCt-1647616558485)(D:\Typora笔记\图片\image-20220313165707436.png)]

虽然结构众多,但重点掌握两种:

  • **无头单向非循环链表:**结构简单,一般不会单独用来存储数据。实际中更多时作为其他数据结构的子结构,如哈希桶,图的邻接表等。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1o9J2R8z-1647616558486)(D:\Typora笔记\图片\image-20220313170012616.png)]

  • **无头双向链表:**在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

链表的模拟实现

无头单向非循环链表

// 1、无头单向非循环链表实现
public class SingleLinkedList {
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    public boolean addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key);
    //删除第一次出现关键字为key的节点
    public void remove(int key);
    //删除所有值为key的节点
    public void removeAllKey(int key);
    //得到单链表的长度
    public int size();
    public void toString();
    public void clear();
}
package singleLinkedList;

/**
 * Created with IntelliJ IDEA
 * Description:结点
 * User: 16037
 * Date: 2022-03-12
 * Time:14:25
 */
public class Node {
    public int val;         //结点值
    public Node next;       //下一个结点引用

    public Node(int val) {
        this.val = val;
    }
}



/**

 * Created with IntelliJ IDEA
 * Description:无头单向非循环链表的简单模拟
 * User: 16037
 * Date: 2022-03-12
 * Time:14:28
   */

public class SingleLinkedList {
    public Node head;       //用成员变量来引用局部生成的Node,局部Node就不会被回收
    public int usedSize;
    
    //头插法
    public void addFirst(int data){
        Node node = new Node(data);
        node.next = this.head;
        this.head = node;
        this.usedSize++;
    }
    //尾插法
    public void addLast(int data) {
        Node node = new Node(data);
        if (this.head == null){
            this.head = node;
        }else {
            Node cur = this.head;
            while(cur.next!=null){
                cur = cur.next;
            }
            cur.next = node;
        }
        this.usedSize++;
    }

​    /**

   * 寻找下标为index的结点
      @param index

        * @return 存在返回下标为index的结点cur,否则返回null
          /
              private Node searchIndex(int index){
          //对index合法性判断
          if(index < 0 || index >= this.usedSize){
              return null;
          }

     Node cur = this.head;
     for(int i = 0;i < index;i++){
         cur = cur.next;
     }
     return cur;
         }
         //任意位置插入,第一个数据节点为0号下标
         public boolean addIndex(int index,int data){
     //头插
     if(index == 0){
         addFirst(data);
         return true;
     }
     //寻找index前一个,为头插时无法处理,列出处理
     Node cur = searchIndex(index-1);
     if(cur == null)
         return false;
     Node node = new Node(data);
     node.next = cur.next;
     cur.next = node;
     this.usedSize++;
     return true;
         }
         //查找是否包含关键字key是否在单链表当中
         public boolean contains(int key){
     Node cur = this.head;
     while(cur!=null){
         //引用类型 equals
         if(cur.val==key)
             return true;
         cur=cur.next;
     }
     return false;
         }

​    /**

   * 找到关键字key的前驱结点,默认初始prev为head
      @param key

        * @return 存在返回prev,不存在返回null
          /
              private Node findPrevKey(int key){

     Node prev = this.head;
     Node findKey = prev.next;
     while(findKey!=null){
         if(findKey.val == key){
             return prev;
         }
         prev = findKey;
         findKey = findKey.next;
     }
     return null;
         }
         //删除第一次出现关键字为key的节点
         public void remove(int key){
     //链表中无结点
     if(this.head == null){
         return;
     }

     //所删结点为头结点
     if(this.head.val == key){
         this.head = this.head.next;
         this.usedSize--;
         return;
     }

     Node prev = findPrevKey(key);
     //无关键字为key的前驱
     if(prev == null)
         return;

     Node del = prev.next;
     prev.next = del.next;
     this.usedSize--;

​    }
​    //删除所有值为key的节点
​    public void removeAllKey(int key){
​        Node del = this.head;
​        Node pre = null;
​        while(del!=null){
​            //所删结点为头结点
​            if(del.val==key && pre == null){
​                this.head = del.next;
​                del = del.next;
​                this.usedSize--;
​                continue;
​            }else if(del.val==key) {
​                pre.next = del.next;
​                del = del.next;
​                this.usedSize--;
​                continue;
​            }
​            pre = del;
​            del=del.next;
​        }
​    }
​    //得到单链表的长度
​    public int size(){
​        return this.usedSize;
​    }

​    @Override
​    public String toString(){
​        StringBuffer s = new StringBuffer();
​        if(this.head == null){
​            s.append("[]");
​            return s.toString();
​        }

​        s.append('[');
​        Node cur = this.head;
​        while(cur!=null){
​            s.append(cur.val);
​            if(cur.next != null)
​                s.append(',');
​            cur=cur.next;
​        }
​        s.append(']');
​        return s.toString();
​    }

​    public void clear(){
​        this.head = null;
​        this.usedSize = 0;
​    }
}

无头双向链表实现

// 2、无头双向链表实现
public class DoubleLinkedList {
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    public boolean addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key);
    //删除第一次出现关键字为key的节点
    public void remove(int key);
    //删除所有值为key的节点
    public void removeAllKey(int key);
    //得到单链表的长度
    public int size();
    public void toString();
    public void clear();
}
package doubleLinkedList;

/**
 * Created with IntelliJ IDEA
 * Description:
 * User: 16037
 * Date: 2022-03-13
 * Time:20:10
 */
public class Node {
    public int val;
    public Node prev;
    public Node next;

    public Node(int val) {
        this.val = val;
    }
}


package doubleLinkedList;

/**
 * Created with IntelliJ IDEA
 * Description:
 * User: 16037
 * Date: 2022-03-16
 * Time:16:17
 */
public class DoubleLinkedList {
    public Node head;
    public Node last;
    public int usedSize;

    public void addFirst(int data){
        if(this.head == null){
            this.head = new Node(data);
            this.last = this.head;
        }else{
            Node node = new Node(data);
            node.next = this.head;
            this.head.prev = node;
            this.head = node;
            this.last = node;
        }
        this.usedSize++;
    }
    public void addLast(int data){
        if(this.head == null){
            addFirst(data);
        }else{
            Node node = new Node(data);
            this.last.next = node;
            node.prev = this.last;
            this.last = node;
            this.usedSize++;
        }
    }

    private Node searchByIndex(int index){
        Node cur = this.head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur;
    }

    public void addIndex(int index,int data){
        if(index < 0 || index > this.usedSize){
            throw new RuntimeException("下标越界!");
        }
        if(index == 0){
            addFirst(data);
        }
        if(index == this.usedSize){
            addLast(data);
        }
        Node next = searchByIndex(index);
        Node node = new Node(data);
        Node prev = next.prev;
        prev.next = node;
        node.prev = prev;
        node.next = next;
        next.prev = node;
        this.usedSize++;
    }

    public boolean contains(int key){
        Node cur = this.head;
        while(cur!=null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    private Node searchByKey(int key){
        Node cur = this.head;
        while(cur!=null){
            if(cur.val == key){
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }
    public void remove(int key){
        if(this.head == null){
            System.out.println("链表为空");
            return ;
        }
        Node del = searchByKey(key);
        if(del == null){
            throw new RuntimeException("无效关键字!");
        }

        if(del == this.head){               //删头结点
            this.head = this.head.next;
            if(this.head == null){      //只有一个结点
                this.last = null;
            }else{
                this.head.prev = null;
            }

        }else if(del == this.last){         //删除尾结点
            this.last = this.last.prev;
            this.last.next = null;
        }else{                              //删除中间结点
            Node prev = del.prev;
            Node next = del.next;
            prev.next = next;
            next.prev = prev;
        }
        this.usedSize--;
    }

    public void removeAllKey(int key){

        if(this.head == null){
            System.out.println("LinkedList is Null!");
            return ;
        }
        if(this.head.val == key && this.head.next == null){
            this.head = null;
            this.last = null;
            this.usedSize--;
            return ;
        }

        Node prev = this.head;
        Node cur = this.head.next;
        while(cur.next != null){
            if(cur.val == key){
                prev.next = cur.next;
                cur.next.prev = prev;
                cur = cur.next;
                this.usedSize--;
                continue;
            }
            cur = cur.next;
            prev = cur;
        }
        if(this.last.val == key){
            this.last = this.last.prev;
            this.last.next = null;
            this.usedSize--;
        }
        if(this.head.val == key){
            this.head = this.head.next;
            if(this.head == null){
                this.last = null;
            }else{
                this.head.prev = null;
            }
            this.usedSize--;
        }
    }

    public int size(){
        return this.usedSize;
    }

    public void clear(){
        Node cur = this.head;
        while(cur!= null){
            Node next = cur.next;
            cur.next = null;
            cur.prev = null;
            cur = next;
        }
        this.head = null;
        this.last = null;
        this.usedSize = 0;
    }

    @Override
    public String toString() {
        StringBuffer str = new StringBuffer();
        if(this.head == null){
            str.append("[]");
            return str.toString();
        }
        str.append('[');
        Node cur = this.head;
        while(cur.next != null){
            str.append(cur.val);
            str.append(',');
            cur = cur.next;
        }
        str.append(cur.val);
        str.append(']');
        return str.toString();
    }
}

LinkedList的使用

什么是LinkedList

LinkedList的底层是无头双向非循环链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TMP0zhFS-1647616558487)(D:\Typora笔记\图片\image-20220313170706769.png)]

在集合框架中,LinkedList也实现了List接口,具体如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IUuK0HZp-1647616558487)(D:\Typora笔记\图片\image-20220313170754251.png)]

【说明】

  1. LinkedList实现了List接口
  2. LinkedList的底层使用了双向链表
  3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

LinkedList的使用

LinkedList的构造

方法解释
LinkedList()无参构造
public LinkedList(Collection<? extends E> c)使用其他集合容器中元素构造List
public static void main(String[] args) {
    // 构造一个空的LinkedList
    List<Integer> list1 = new LinkedList<>();
    List<String> list2 = new java.util.ArrayList<>();
    list2.add("JavaSE");
    list2.add("JavaWeb");
    list2.add("JavaEE");
    // 使用ArrayList构造LinkedList
    List<String> list3 = new LinkedList<>(list2);
}

LinkedList的其他常用方法

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

LinkedList的遍历

public static void main(String[] args) {
    LinkedList<Integer> list = new LinkedList<>();
    list.add(1); // add(elem): 表示尾插
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(5);
    list.add(6);
    list.add(7);
    System.out.println(list.size());
    
    // foreach遍历
    for (int e:list) {
    	System.out.print(e + " ");
    } 
    System.out.println();
    // 使用迭代器遍历---正向遍历
    ListIterator<Integer> it = list.listIterator();
    while(it.hasNext()){
    	System.out.print(it.next()+ " ");
    } 
    System.out.println();
    // 使用反向迭代器---反向遍历
    ListIterator<Integer> rit = list.listIterator(list.size());
    while (rit.hasPrevious()){
    	System.out.print(rit.previous() +" ");
    } 
    System.out.println();
}

最难不过坚持!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值