单向链表实现

1.1 基本介绍

链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。链表中数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域(data)另一个是存储下一个结点地址的指针域(next)。(百度百科)

1.2 存储原理

链表的每一个节点分布在内存的不同位置,依靠next指针关联起来。这样可以灵活有效地利用零散的碎片空间。链表的第1个节点被称为头节点(3),没有任何节点的next指针指向它,或者说它的前置节点为空头结点用来记录链表的基地址。有了它就可以遍历得到整条链表链表的最后1个节点被称为尾节点(2),它指向的next为NULL

1.3 添加操作

1、思路分析

  • 为了让代码更加精简,统一所有节点的处理逻辑,可以在最前面增加一个虚拟的头结点(不存储数据)
  • 新节点的next指针,指向插入位置的节点。插入位置前置节点的next指针,指向新节点。
  • 只要内存空间允许,能够插入链表的元素是无限的,不需要像数组那样考虑扩容的问题。

头部添加

当链表为空时,头部插入

当链表不为空时,从头部插入。

先让新的节点指向头结点,然后再让头结点指向新节点!!!

尾部添加

先让尾指针指向的节点,指向新节点

然后tail从新指向新节点

中间添加

定义一个指针prev,将prev的当前下一跳给新节点的下一跳。然后再让prev节点重新指向新节点

2、代码示例

接口实现:List

package cn.linkedlist.demo01;

/***
 * List接口方法
 * @param <E>
 */
public interface List<E> extends Iterable<E>{
    void add(E element);
    void add(int index, E element) ;
    void remove(E element);
    E remove(int index);
    E get(int index);
    E set(int index, E element) ;
    int size();
    int indexOf(E element) ;
    boolean contains(E element);
    boolean isEmpty();
    void clear();
}

链表实现:LinkedSinglyList

package cn.linkedlist.demo01;

import java.util.Iterator;

public class LinkedSinglyList<E> implements List<E>{
    // 创建Node节点
    private class Node{
        //数据域 用来存储数据的
        public E data;
        //指针域 用来存储下一个结点对象的地址
        public Node next;

        // 构造方法
        public Node() {
            this(null, null);
        }

        public Node(E data) {
            this(data, null);
        }

        public Node(E data, Node next) {
            this.data = data;
            this.next = next;
        }

        @Override
        public String toString(){
            return data.toString();
        }
    }

    // 链表元素的数量
    private int size;
    //链表当中的头指针指向第一个结点对象
    private Node head;
    //链表当中的头指针指向最后一个结点对象
    private Node tail;

    // 初始化链表
    public LinkedSinglyList(){
        head = null;
        tail = null;
        size = 0;
    }

    public LinkedSinglyList(E[] arr){
        for (E e : arr){
            add(e);
        }
    }

    /***
     * 在链表末尾添加新的元素e
     * @param element
     */
    @Override
    public void add(E element) {
        add(size, element);
    }

    /***
     * 根据链表的index位置添加新的元素e
     * @param index
     * @param element
     */
    @Override
    public void add(int index, E element) {
        if (index < 0|| index > size) {
            throw new ArrayIndexOutOfBoundsException("add index out of bounds");
        }
        // 创建新的结点对象
        Node node = new Node(element);

        if(isEmpty()){
            // 链表为空
            head = node;
            tail = node;
        }else if(index == 0){
            // 在链表头部添加元素
            node.next = head;
            head = node;
        }else if(index == size){
            // 在链表尾部添加元素
            tail.next = node;
            tail = node;
        }else{
            // 在链表中添加元素
            Node prev = head;
            for(int i=0; i < index -1; i++){
                prev = prev.next;
            }
            node.next = prev.next;
            prev.next = node;
        }
        size++;
    }
    
    @Override
    public int size() {
        return size;
    }
    /***
     * 判断链表是否为空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return size == 0 && head == null && tail == null;
    }

    @Override
    public void clear() {
        head = null;
        tail = null;
        size = 0;
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append("size=").append(size).append(", [");
        // 定义一个指针变量
        Node cur = head;
        while(cur != null){
            res.append(cur + "->");
            cur = cur.next;
        }
        res.append("NULL");
        res.append("]");
        return res.toString();
    }

    /***
     * 迭代器实现
      * @return
     */
    @Override
    public Iterator<E> iterator() {
        return new LinkedListIterator();
    }

    class LinkedListIterator implements Iterator<E>{
        // 定义游标
        private Node cur = head;
        @Override
        public boolean hasNext() {
            return cur != null;
        }

        @Override
        public E next() {
            E ret = cur.data;
            cur = cur.next;
            return ret;
        }
    }
}

3、测试代码:LinkedSinglyListDemo

package cn.linkedlist.demo01;

public class LinkedSinglyListDemo {
    public static void main(String[] args) {
        LinkedSinglyList<Integer> linkedList = new LinkedSinglyList<>();

        System.out.println("===链表头部插入===");
        linkedList.add(0,1);
        linkedList.add(0,3);
        linkedList.add(0,5);
        linkedList.add(0,8);
        System.out.println(linkedList);

        System.out.println("==链表尾部插入==");
        linkedList.add(12);
        System.out.println(linkedList);

        System.out.println("===链表中间插入===");
        linkedList.add(2, 23);
        System.out.println(linkedList);
    }
}

4、执行结果

1.4 查询和修改

1、查询操作

链表:SingleLinkedList

/***
 * 得链表的第index个位置的元素
 * @param index
 * @return
*/
@Override
public E get(int index) {
    if (index < 0|| index > size) {
        throw new ArrayIndexOutOfBoundsException("get index out of bounds");
    }
    // 获取头部
    if(index == 0){
        return head.data;
    }else if(index == size -1){
        // 获取尾部
        return tail.data;
    }else{
        // 获取中间
        Node prev = head;
        for (int i = 0; i < index; i++) {
            prev = prev.next;
        }
        return prev.data;
    }
}

/***
 * 查找元素在链表中第一次出现的索引
 * @param element
 * @return
*/
@Override
public int indexOf(E element) {
    // 判断链表是否为空
    if(isEmpty()){
        return -1;
    }
    // 定义prev指针
    Node prev = head;
    // 定义索引值
    int index = 0;
    while (!prev.data.equals(element)){
        prev = prev.next;
        index++;
        // 如果没有找到,则返回-1
        if(prev == null){
            return -1;
        }
    }
    return index;
}

/***
 * 查找链表中是否有元素element
 * @param element
 * @return
*/
@Override
public boolean contains(E element) {
    return indexOf(element)!= -1;
}

测试代码:LinkedSinglyListDemo

package cn.linkedlist.demo01;

public class LinkedSinglyListDemo {
    public static void main(String[] args) {
        LinkedSinglyList<Integer> linkedList = new LinkedSinglyList<>();

        System.out.println("===插入元素===");
        linkedList.add(0,1);
        linkedList.add(0,3);
        linkedList.add(0,5);
        linkedList.add(0,8);
    
        linkedList.add(12);
        linkedList.add(2, 23);
        System.out.println(linkedList);

        System.out.println("===查找元素===");
        Integer integer = linkedList.get(2);
        System.out.println("通过索引获取元素:" + integer);
        boolean b = linkedList.contains(23);
        System.out.println("是否存在该元素:" + b);
        int element = linkedList.indexOf(12);
        System.out.println("该元素的索引:" + element);
    }
}

2、执行结果

3、修改节点

找到要更新的节点,然后把旧数据替换成新数据。

4、代码示例

链表:LinkedSinglyList

/***
 * 修改链表中指定index的元素为element
 * @param index
 * @param element
 * @return
*/
@Override
public E set(int index, E element) {
    if (index < 0|| index > size) {
        throw new ArrayIndexOutOfBoundsException("update index out of bounds");
    }
    // 定义返回值
    E result = null;
    if(index == 0){
        // 修改头部
        result= head.data;
        head.data = element;
    }else if(index == size -1){
        // 修改尾部
        result = tail.data;
        tail.data = element;
    }else{
        // 修改中间的元素
        Node prev = head;
        for (int i = 0; i < index; i++) {
            prev = prev.next;
        }
        result = prev.data;
        prev.data = element;
    }
    return result;
}

测试代码:LinkedSinglyListDemo

package cn.linkedlist.demo01;

public class LinkedSinglyListDemo {
    public static void main(String[] args) {
        LinkedSinglyList<Integer> linkedList = new LinkedSinglyList<>();

        System.out.println("===插入元素===");
        linkedList.add(0,1);
        linkedList.add(0,3);
        linkedList.add(0,5);
        linkedList.add(0,8);
       
        linkedList.add(12);
       
        linkedList.add(2, 23);
        System.out.println(linkedList);

        System.out.println("===修改节点元素===");
        System.out.println("LinkedSinglyList(修改前)" + linkedList);
        linkedList.set(4, 38);
        System.out.println("LinkedSinglyList(修改后)" + linkedList);
    }
}

5、执行结果

1.5 删除操作

1、思路分析

把要删除节点的前置节点的next指针,指向要删除元素的下一个节点即可。

删除头结点

head 指向下一个元素

然后让之前的元素断开

删除尾节点

定义一个prev指针,直接找到尾节点前面那个元素。

让当前prev的下一个元素,执行置空操作。

然后让尾指针指向该元素

删除中间元素

先找到要删除节点的前驱,让删除节点前一个元素指向要删除元素的后继

然后将要删除节点的后继置空

链表只有一个元素

直接让headtail置空即可

2、代码示例

链表:LinkedSinglyList

/***
 * 删除链表中指定的元素element
 * @param element
 */
@Override
public void remove(E element) {
    int index = indexOf(element);
    if(index != -1){
        remove(index);
    }
}
/***
 * 删除链表中指定索引处index的元素
 * @param index
 * @return
*/
@Override
public E remove(int index) {
    if (index < 0|| index > size) {
        throw new ArrayIndexOutOfBoundsException("remove index out of bounds");
    }
    // 定义返回值
    E result = null;
    // 当链表只剩下一个元素
    if(size == 1){
        result = head.data;
        head = null;
        tail = null;
    }else if(index == 0){
        // 删除链表头部
        Node prev = head;
        result = prev.data;
        head = prev.next;
        // 置空操作
        prev.next = null;
    }else if(index == size -1){
        // 删除链表尾部
        Node prev = head;
        while (prev.next != tail){
            prev = prev.next;
        }
        result = tail.data;
        // 置空操作
        prev.next = null;
        tail = prev;
    }else{
        // 删除中间的某个元素
        Node prev = head;
        for (int i = 0; i < index -1; i++) {
            prev = prev.next;
        }
        Node deleteNode = prev.next;
        result = deleteNode.data;
        prev.next = deleteNode.next;
        // 置空
        deleteNode.next = null;
    }
    size --;
    return result;
}

测试代码:LinkedSinglyListDemo

package cn.linkedlist.demo01;

public class LinkedSinglyListDemo {
    public static void main(String[] args) {
        LinkedSinglyList<Integer> linkedList = new LinkedSinglyList<>();

        System.out.println("===插入元素===");
        linkedList.add(0,1);
        linkedList.add(0,3);
        linkedList.add(0,5);
        linkedList.add(0,8);
        linkedList.add(12);
        
        linkedList.add(2, 23);
        System.out.println(linkedList);

        System.out.println("===删除链表节点前====");
        System.out.println(linkedList);
        System.out.println("===删除链表节点后====");
        // 根据链表index位置的元素, 返回删除的元素
        linkedList.remove(2);
        System.out.println(linkedList);

        // 删除链表中的元素
        linkedList.remove(0);
        System.out.println(linkedList);
    }
}

3、执行结果

posted @ 2021-12-27 10:47  guardwhy  阅读(39)  评论(0编辑  收藏  举报