双向链表——模拟LinkedList的实现(java)

LinkedList底层用双向链表来实现,提高了很多效率。其中有许多值的一看的方法:例如在getNode(int i)方法中,可以先让索引值i与中间值比较,再确定是从前到后遍历还是从后到前遍历,提高了查找效率。在add(int i, Object e)方法中判断索引是否等于size,如果等于size就直接添加,减少了遍历次数,下面是代码。

package com.qianyu.dataStructure.lineTable;

/**
 * @author lijing
 * @date 2019-03-22-14:26
 * @discroption 模拟实现LinkedList
 */
public class LinkedList implements List {
    /**
     * 内部类,定义结点类
     */
    private class Node {
        Node pre;//前一个结点
        Node next;//后一个结点
        Object data;//储存数据

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

    private Node first;//指向第一个元素
    private Node last;//指向最后一个元素
    private int size;//LinkedList的长度

    /**
     * 空构造函数,所有成员均为null
     */
    public LinkedList() {
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public Object get(int i) {
        //先判断是否越界
        checkElementIndex(i, false);
        //获取指定索引的结点
        return this.getNode(i).data;
    }

    /**
     * 获取指定索引的结点
     *
     * @param i
     * @return
     */
    private Node getNode(int i) {
        //为了提高效率,可以先让索引值i与中间值比较,再确定是从前到后遍历还是从后到前遍历
        if (i < (this.size >> 1)) {
            //从前到后遍历
            Node p = this.first;
            for (int j = 0; j < i; j++) {
                p = p.next;
            }
            return p;
        } else {
            //从后往前遍历
            Node p = this.last;
            for (int j = this.size - 1; j > i; j--) {
                p = p.pre;
            }
            return p;
        }
    }

    /**
     * 判断索引是否越界
     *
     * @param i     索引
     * @param isAdd 是否是添加元素操作
     */
    private void checkElementIndex(int i, boolean isAdd) {
        if (!isAdd) {
            //如果不是添加操作,不能索引到size
            if (i < 0 || i >= this.size) {
                throw new MyIndexOutOfBoundsException("无效的索引:" + i);
            }
        } else {
            //如果是添加操作,在索引size出添加相当于在末尾追加
            if (i < 0 || i > this.size) {
                throw new MyIndexOutOfBoundsException("无效的索引:" + i);
            }
        }
    }

    @Override
    public boolean isEmpty() {
        return size > 0;
    }

    @Override
    public boolean contains(Object e) {
        //调用indexOf()函数,如果返回值不是-1就说明在LinkedList中没有找到e
        return this.indexOf(e) != -1;
    }

    @Override
    public int indexOf(Object e) {
        Node p = this.first;
        int index = 0;
        //先判断e是否为空
        if (e == null) {
            while (p != null) {
                if (p.data == null) {
                    return index;
                }
                index++;
                p = p.next;
            }
        } else {
            while (p != null) {
                if (p.data.equals(e)) {
                    return index;
                }
                index++;
                p = p.next;
            }
        }
        return -1;
    }

    @Override
    public void add(int i, Object e) {
        //先检查索引是否越界
        checkElementIndex(i, true);

        //判断如果索引值和size相同,就调用add(Object e)方法,省去了遍历链表的操作,提高了效率
        if (i == size) {
            this.add(e);
        } else {
            Node node = getNode(1);//索引为i的结点
            Node p = node.pre;//索引为i的结点的前一个结点
            Node newNode = new Node(p, node, e);//带插入的新结点
            node.pre = newNode;//将原来索引为i的结点的前驱指向新的结点
            //判断是否是第一次插入
            if (p == null) {
                this.first = newNode;
            } else {
                p.next = newNode;
            }
            //将size加一
            size++;
        }

    }

    @Override
    public void add(Object e) {
        //1.新建一个节点,将其前驱节点设置为last,后继节点设置为null,数据域设为e
        Node newNode = new Node(this.last, null, e);
        //2.储存旧尾指针
        Node l = this.last;
        //3.修改尾指针
        this.last = newNode;
        //4.判断l是否为空
        if (l == null) {
            //如果为空就代表是第一次添加,要将头指针指向newNode
            this.first = newNode;
        } else {
            //如果非空就代表不是第一次添加,不用只用将原来的尾指针的next指向newNode即可
            l.next = newNode;
        }
        //5.将长度加一
        this.size++;
    }

    @Override
    public Object remove(int i) {
        //先检查索引是否越界
        checkElementIndex(i, false);

        Node p = this.first;
        //遍历找到要删除的结点
        for (int j = 0; j < i; j++) {
            p = p.next;
        }
        return unlink(p);
    }

    @Override
    public boolean remove(Object e) {
        //先判断是否为null
        Node p = this.first;
        if (e == null) {
            while (p != null) {
                if (p.data == null) {
                    //如果找到结点就调用删除结点的方法
                    unlink(p);
                    return true;
                }
                p = p.next;
            }
        } else {
            while (p != null) {
                if (p.data.equals(e)) {
                    //如果找到结点就调用删除结点的方法
                    unlink(p);
                    return true;
                }
                p = p.next;
            }
        }
        return false;
    }

    /**
     * 删除结点p
     *
     * @param p 要删除的结点
     */
    private Object unlink(Node p) {
        Node preNode = p.pre;
        Node nextNode = p.next;

        //先处理要删除结点的前一个结点
        if (preNode == null) {
            this.first = nextNode;
        } else {
            preNode.next = nextNode;
            p.pre = null;
        }

        //处理后一个结点
        if (nextNode == null) {
            this.last = preNode;
        } else {
            p.next = null;
            nextNode.pre = preNode;
        }

        this.size--;
        return p.data;
    }

    @Override
    public Object replace(int i, Object e) {
        //先检查索引是否越界
        checkElementIndex(i, false);

        Node p = this.first;
        //遍历找到要替换的结点
        for (int j = 0; j < i; j++) {
            p = p.next;
        }
        Object temp = p.data;
        p.data = e;
        return temp;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        Node p = this.first;
        int index = 0;
        while (p != null) {
            if (index != size - 1) {
                sb.append(p.data.toString() + ",");
            } else {
                sb.append(p.data.toString());
            }
            p = p.next;
            index++;
        }
        sb.append("]");
        return sb.toString();
    }
}

猜你喜欢

转载自blog.csdn.net/li3455277925/article/details/88776194