Java-双向链表的实现


一、概述

双向链表也称为双链表,是链表的一种,它的每个数据节点都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个节点开始,都可以很方便地访问它的前驱节点和后继节点。

在这里插入图片描述

双向列表的特点:

  1. 可以使用一个 headtail 分别指向头部和尾部的节点
  2. 每个节点由三部分组成:
    • 前一个节点的指针 prev
    • 保存的元素 data
    • 后一个节点的指针 next
  3. 双向链表的第一个节点的 pre 是 null
  4. 双向链表的最后一个节点的 next 是 null

双向链表在进行增加和删除元素的时候,只需要改变 prevnext 的指向即可完成相关的操作。

增加节点

  • 从头端插入节点
    在这里插入图片描述

  • 从中间位置插入节点
    在这里插入图片描述

  • 从尾端插入节点
    在这里插入图片描述

删除节点

  • 从头端删除节点
    在这里插入图片描述
  • 从中间位置删除节点
    在这里插入图片描述
  • 从尾端删除节点
    在这里插入图片描述

二、手写双向链表

创建 DoubleLinkedList 类,该类中写一个内部类 Node作为节点对象,Node 中拥有的属性是 datanextprev 分别对应 所保存的数据下一个节点对象上一个节点对象DoubleLinkedList 链表对象所拥有的属性为 headtailsize,分别对应头节点尾节点链表长度

/**
 * 双向链表
 * @param <E>
 */
public class DoubleLinkedList<E> {

    // 头节点
    private Node<E> head;
    // 尾节点
    private Node<E> tail;
    // 长度
    private int size;

    public DoubleLinkedList() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    // 内部类:节点对象
    private static class Node<E> {
        E data;
        Node<E> next;
        Node<E> prev;

        // 无参构造
        public Node() {
            this.data = null;
            this.next = null;
            this.prev = null;
        }

        // 构造方法
        public Node(Node<E> prev, E data, Node<E> next) {
            this.data = data;
            this.next = next;
            this.prev = prev;
        }

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

void add(E element) 方法

    // 往链表末端添加元素
    public void add(E element) {
        this.add(size,element);
    }

void add(int index,E element) 方法

    // 往指定位置添加元素
    public void add(int index,E element) {

        if (index > size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        Node<E> node = new Node<>();
        node.data = element;
        // 判断当前链表的长度是否为 0
        if (size == 0) {
            // 如果为 0 ,则表示当前为第一次添加元素,头节点和尾节点就是新添加的节点
            head = node;
            tail = node;
        } else {
            if (index == 0) {
                // 从头端插入元素
                node.next = head;
                head.prev = node;
                head = node;
            } else if (index == size) {
                // 从尾端插入元素
                node.prev = tail;
                tail.next = node;
                tail = node;
            } else {
                // 从链表的间件位置插入元素
                // p:表示之前在 index 位置上的节点
                // q:表示之前在 index - 1 位置上的节点
                Node<E> p,q;
                // 遍历链表
                p = head;
                int count = 0;
                while (p.next != null) {
                    if (count == index) {
                        break;
                    }
                    p = p.next;
                    count++;
                }
                q = p.prev;
                node.prev = q;
                node.next = p;
                q.next = node;
                p.prev = node;
            }
        }
        size++;
    }

E remove() 方法

    // 删除链表末端元素
    public E remove() {
        return this.remove(size);
    }

E remove(E element) 方法

    // 删除链表中指定元素
    public E remove(E element) {
        int index = indexOf(element);
        if (index != -1) {
            return this.remove(index);
        }
        return null;
    }

E remove(int index) 方法

    // 删除链表中指定下标元素
    public E remove(int index) {

        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        E ret;

        if (index == 0) {
            // 删除头节点
            ret = head.data;
            Node<E> node = head.next;
            head.next = null;
            node.prev = null;
            head = node;
        } else if (index == size-1) {
            // 删除尾节点
            ret = tail.data;
            Node<E> node = tail.prev;
            tail.prev = null;
            node.next = null;
            tail = node;
        } else {
            // 删除中间位置的某个元素
            // p:表示 index 位置上的节点
            // q:表示 index - 1 位置上的节点
            // y:表示 index + 1 位置上的节点
            Node<E> p,q,y;
            // 遍历链表
            p = head;
            int count = 0;
            while (p.next != null) {
                if (count == index) {
                    break;
                }
                p = p.next;
                count++;
            }
            ret = p.data;
            y = p.next;
            q = p.prev;
            q.next = y;
            y.prev = q;
        }
        size--;
        return ret;
    }

int indexOf(E element) 方法

    // 获取指定元素的下标
    public int indexOf(E element) {
        int index = 0;
        Node<E> p = head;
        while (!p.data.equals(element)) {
            index++;
            p = p.next;
            if (index >= size) {
                return -1;
            }
        }
        return index;
    }

E get(int index) 方法

    // 获取指定下标的元素
    public E get(int index) {
        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }
        if (index == 0) {
            return head.data;
        } else if (index == size-1) {
            return tail.data;
        } else {
            Node<E> p = head;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            return p.data;
        }
    }

E set(int index,E element) 方法

    // 设置指定下标的值
    public E set(int index,E element) {

        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        E ret;
        if (index == 0) {
            ret = head.data;
            head.data = element;
        } else if (index == size-1) {
            ret = tail.data;
            tail.data = element;
        } else {
            Node<E> p = head;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            ret = p.data;
            p.data = element;
        }

        return ret;
    }

int size() 方法

    // 返回链表长度
    public int size() {
        return size;
    }

boolean contains(E element) 方法

    // 指定元素是否在链表中存在
    public boolean contains(E element) {
        return indexOf(element) != -1;
    }

boolean isEmpty() 方法

    // 当前链表是否为空链表
    public boolean isEmpty() {
        return size == 0;
    }

void clear() 方法

    // 清空链表
    public void clear() {
        head = null;
        tail = null;
        size = 0;
    }

void sort(Comparator comparator) 方法

    // 排序
    public void sort(Comparator<E> comparator) {

        if (comparator == null) {
            throw new IllegalArgumentException("comparable can not null");
        }

        if (size == 0 || size == 1) {
            return;
        }
        // 选则排序
        Node<E> nodeA = head;
        Node<E> nodeB = nodeA.next;
        while (nodeA.next != tail) {
            while (nodeB != tail) {
                if (comparator.compare(nodeA.data,nodeB.data) > 0) {
                    E temp = nodeA.data;
                    nodeA.data = nodeB.data;
                    nodeB.data = temp;
                }
                nodeB = nodeB.next;
            }
            nodeA = nodeA.next;
            nodeB = nodeA.next;
        }
    }

DoubleLinkedList subList(int fromIndex,int toIndex) 方法

    // 截取链表
    public DoubleLinkedList<E> subList(int fromIndex,int toIndex) {
        if (fromIndex < 0 || toIndex >= size || fromIndex > toIndex) {
            throw new IllegalArgumentException("Illegal Index" );
        }
        Node<E> nodeA = head;
        for (int i = 0; i < fromIndex; i++) {
            nodeA = nodeA.next;
        }
        Node<E> nodeB = head;
        for (int i = 0; i < toIndex; i++) {
            nodeB = nodeB.next;
        }
        DoubleLinkedList<E> list = new DoubleLinkedList<>();
        Node<E> p = nodeA;
        while (p != nodeB) {
            list.add(p.data);
            p = p.next;
        }
        return list;
    }

四、完整代码

import java.util.Comparator;

/**
 * 双向链表
 * @param <E>
 */
public class DoubleLinkedList<E> {

    // 头节点
    private Node<E> head;
    // 尾节点
    private Node<E> tail;
    // 长度
    private int size = 0;

    public DoubleLinkedList() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

    // 内部类:节点对象
    private static class Node<E> {
        E data;
        Node<E> next;
        Node<E> prev;

        // 无参构造
        public Node() {
            this.data = null;
            this.next = null;
            this.prev = null;
        }

        // 构造方法
        public Node(Node<E> prev, E data, Node<E> next) {
            this.data = data;
            this.next = next;
            this.prev = prev;
        }

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

    // 往链表末端添加元素
    public void add(E element) {
        this.add(size,element);
    }

    // 往指定位置添加元素
    public void add(int index,E element) {

        if (index > size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        Node<E> node = new Node<>();
        node.data = element;
        // 判断当前链表的长度是否为 0
        if (size == 0) {
            // 如果为 0 ,则表示当前为第一次添加元素,头节点和尾节点就是新添加的节点
            head = node;
            tail = node;
        } else {
            if (index == 0) {
                // 从头端插入元素
                node.next = head;
                head.prev = node;
                head = node;
            } else if (index == size) {
                // 从尾端插入元素
                node.prev = tail;
                tail.next = node;
                tail = node;
            } else {
                // 从链表的间件位置插入元素
                // p:表示之前在 index 位置上的节点
                // q:表示之前在 index - 1 位置上的节点
                Node<E> p,q;
                // 遍历链表
                p = head;
                int count = 0;
                while (p.next != null) {
                    if (count == index) {
                        break;
                    }
                    p = p.next;
                    count++;
                }
                q = p.prev;
                node.prev = q;
                node.next = p;
                q.next = node;
                p.prev = node;
            }
        }
        size++;
    }

    // 删除链表末端元素
    public E remove() {
        return this.remove(size);
    }

    // 删除链表中指定元素
    public E remove(E element) {
        int index = indexOf(element);
        if (index != -1) {
            return this.remove(index);
        }
        return null;
    }

    // 删除链表中指定下标元素
    public E remove(int index) {

        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        E ret;

        if (index == 0) {
            // 删除头节点
            ret = head.data;
            Node<E> node = head.next;
            head.next = null;
            node.prev = null;
            head = node;
        } else if (index == size-1) {
            // 删除尾节点
            ret = tail.data;
            Node<E> node = tail.prev;
            tail.prev = null;
            node.next = null;
            tail = node;
        } else {
            // 删除中间位置的某个元素
            // p:表示 index 位置上的节点
            // q:表示 index - 1 位置上的节点
            // y:表示 index + 1 位置上的节点
            Node<E> p,q,y;
            // 遍历链表
            p = head;
            int count = 0;
            while (p.next != null) {
                if (count == index) {
                    break;
                }
                p = p.next;
                count++;
            }
            ret = p.data;
            y = p.next;
            q = p.prev;
            q.next = y;
            y.prev = q;
        }
        size--;
        return ret;
    }

    // 获取指定元素的下标
    public int indexOf(E element) {
        int index = 0;
        Node<E> p = head;
        while (!p.data.equals(element)) {
            index++;
            p = p.next;
            if (index >= size) {
                return -1;
            }
        }
        return index;
    }

    // 获取指定下标的元素
    public E get(int index) {
        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }
        if (index == 0) {
            return head.data;
        } else if (index == size-1) {
            return tail.data;
        } else {
            Node<E> p = head;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            return p.data;
        }
    }

    // 设置指定下标的值
    public E set(int index,E element) {

        if (index >= size || index < 0) {
            throw new IllegalArgumentException("Illegal Index:" + index);
        }

        E ret;
        if (index == 0) {
            ret = head.data;
            head.data = element;
        } else if (index == size-1) {
            ret = tail.data;
            tail.data = element;
        } else {
            Node<E> p = head;
            for (int i = 0; i < index; i++) {
                p = p.next;
            }
            ret = p.data;
            p.data = element;
        }

        return ret;
    }

    // 返回链表长度
    public int size() {
        return size;
    }

    // 指定元素是否在链表中存在
    public boolean contains(E element) {
        return indexOf(element) != -1;
    }

    // 当前链表是否为空链表
    public boolean isEmpty() {
        return size == 0;
    }

    // 清空链表
    public void clear() {
        head = null;
        tail = null;
        size = 0;
    }

    // 排序
    public void sort(Comparator<E> comparator) {

        if (comparator == null) {
            throw new IllegalArgumentException("comparable can not null");
        }

        if (size == 0 || size == 1) {
            return;
        }
        // 选则排序
        Node<E> nodeA = head;
        Node<E> nodeB = nodeA.next;
        while (nodeA.next != tail) {
            while (nodeB != tail) {
                if (comparator.compare(nodeA.data,nodeB.data) > 0) {
                    E temp = nodeA.data;
                    nodeA.data = nodeB.data;
                    nodeB.data = temp;
                }
                nodeB = nodeB.next;
            }
            nodeA = nodeA.next;
            nodeB = nodeA.next;
        }
    }

    // 截取链表
    public DoubleLinkedList<E> subList(int fromIndex,int toIndex) {
        if (fromIndex < 0 || toIndex >= size || fromIndex > toIndex) {
            throw new IllegalArgumentException("Illegal Index" );
        }
        Node<E> nodeA = head;
        for (int i = 0; i < fromIndex; i++) {
            nodeA = nodeA.next;
        }
        Node<E> nodeB = head;
        for (int i = 0; i < toIndex; i++) {
            nodeB = nodeB.next;
        }
        DoubleLinkedList<E> list = new DoubleLinkedList<>();
        Node<E> p = nodeA;
        while (p != nodeB) {
            list.add(p.data);
            p = p.next;
        }
        return list;
    }
}

五、测试代码

public class TextDem {
    public static void main(String[] args) {
        DoubleLinkedList<String> list = new DoubleLinkedList<>();
        // 添加元素
        list.add("米大傻");
        list.add("米二傻");
        list.add("米三傻");
        list.add("米四傻");
        list.add("米五傻");
        list.add(1,"米六傻");
        list.add(0,"米七傻");
        // 删除指定下标元素
        list.remove(3);
        // 查找元素下标
        int index = list.indexOf("米四傻");
        System.out.println("index = " + index);
        // 设置指定下标的值
        list.set(2,"李大霄");

        // 遍历集合
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        System.out.println("====================");
        // 截取集合
        DoubleLinkedList<String> subList = list.subList(2, 5);
        for (int i = 0; i < subList.size(); i++) {
            System.out.println(subList.get(i));
        }

        System.out.println("====================");
        // 清空集合
        list.clear();
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值