链表

1、链表的介绍

链表是一种线性存储结构,拥有n(n>=0)个同类型的元素组成,链表中的元素通常包含数据和一个或两个指向其他节点的引用。

2、java实现单向链表(可以存储任意类型)

首先写一个通用的接口:

interface Link<T>{
    public void addFirst(T item);
    public void addLast(T item);
    public T getFisrt();
    public T getLast();
    public T get(int index);
    public void set(int index,T item);
    public void insert(int index,T item);
    public T del(int index);
    public T removeFirst();
    public T removeLast();
    public int size();
    public boolean isNull();
    public void printLink();
    public boolean chechIndex(int index);
    public boolean checkPosition(int index);
}

单链表实现类:

class SLink<T> implements Link<T>{
    private int size = 0;
    private Node<T> first;
    private Node<T> last;
    private static class Node<T>{
        T item;
        Node<T> next;
        Node(T item,Node<T> nextNode){
            this.item = item;
            this.next = nextNode;
        }
    }
    @Override
    public void addFirst(T item) {
        // TODO Auto-generated method stub
        Node<T> newNode = new Node<T>(item, first);
        if(first == null){
            first = newNode;
            last = newNode;
        }else {
            first = newNode;
        }
        size++;
    }
    @Override
    public void addLast(T item) {
        // TODO Auto-generated method stub

        Node<T> newNode = new Node<T>(item, null);
        if(last == null){
            first = newNode;
            last = newNode;
        }else {
            last.next = newNode;
            last = newNode;
        }
        size++;
    }
    @Override
    public T getFisrt() {
        // TODO Auto-generated method stub
        if(first == null)
            throw new NoSuchElementException();
        return first.item;
    }
    @Override
    public T getLast() {
        // TODO Auto-generated method stub
        if(last == null)
            throw new NoSuchElementException();
        return last.item;
    }
    @Override
    public T get(int index) {
        // TODO Auto-generated method stub
        if(!chechIndex(index))
            throw new IndexOutOfBoundsException("index超出限度");
        T item = null;
        Node<T> node = first;
        for (int i = 0; i <= index; i++) {
            if(i == index)
                item =  node.item;
            node = node.next;
        }
        return item;
    }
    @Override
    public void set(int index, T item) {
        // TODO Auto-generated method stub
        if(!chechIndex(index))
            throw new IndexOutOfBoundsException("index超出限度");
        Node<T> node = first;
        for (int i = 0; i <= index; i++) {
            if(i == index)
                node.item = item;
            node = node.next;
        }
    }
    @Override
    public void insert(int index, T item) {
        // TODO Auto-generated method stub
        if(!checkPosition(index))
            throw new IndexOutOfBoundsException("index超出限度");
        Node<T> node = first;
        Node<T> node1 = null;
        Node<T> newNode = new Node<T>(item, null);
        if (index == size) {
            addLast(item);
        }
        else if (index == 0) {
            addFirst(item);
        }
        else {
            for (int i = 0; i <= index; i++) {
                if(i == index - 1){
                    //保存原来索引位置的值
                    node1 = node.next;
                    //将新节点插入到原位置
                    node.next = newNode;
                }
                else if(i == index){
                    //新节点连上原来位置的节点
                    node.next = node1;
                }
                node = node.next;
            }
            size++;
        }
    }
    @Override
    public T removeFirst() {
        // TODO Auto-generated method stub
        T item = null;
        if(first == null)
            throw new IndexOutOfBoundsException("index超出限度");
        item = first.item;
        first = first.next;
        if(first == null)
            last = null;
        size--;
        return item;
    }
    @Override
    public T removeLast() {
        // TODO Auto-generated method stub
        T item = null;
        Node<T> node = first;
        if(last == null)
            throw new IndexOutOfBoundsException("index超出限度");
        item = last.item;
        if(size == 1)
            removeFirst();
        else if(size>1){
            for (int i = 0; i < size-1; i++) {
                if(i == size-2){
                    node.next = null;
                    last = node;
                }
                node = node.next;
            }
            size--;
        }
        return item;
    }
    @Override
    public T del(int index) {
        if(!chechIndex(index))
            throw new IndexOutOfBoundsException("index超出限度");
        T item = null;
        Node<T> node = first;
        Node<T> node1 = null;
        if(index == 0){
            item = removeFirst();
        }
        else if (index == size - 1) {
            item = removeLast();
        }
        else {
            for (int i = 0; i <= index + 1; i++) {
                if(i == index - 1){
                    //保存索引位置前一个点
                    node1 = node;
                }
                else if(i == index){
                    item = node.item;
                    node1.next = node.next;
                }
                node = node.next;
            }
            size--;
        }
        return item;
    }
    @Override
    public int size() {
        // TODO Auto-generated method stub
        return size;
    }
    @Override
    public boolean isNull() {
        // TODO Auto-generated method stub
        return size == 0;
    }
    @Override
    public void printLink() {
        // TODO Auto-generated method stub
        Node<T> node = first;
        for (int i = 0; i < size; i++) {
            System.out.print(node.item);
            node = node.next;
        }
        System.out.println();
    }
    @Override
    public boolean chechIndex(int index) {
        // TODO Auto-generated method stub
        return index<size&&index>=0;
    }
    @Override
    public boolean checkPosition(int index) {
        // TODO Auto-generated method stub
        return index<=size&&index>=0;
    }
}

操作示例:

        SLink<Integer> sLink = new SLink<>();
        sLink.addFirst(1);
        sLink.addFirst(2);
        sLink.addFirst(3);
        sLink.addLast(4);
        sLink.removeLast();
        sLink.insert(0, 4);
        sLink.removeLast();
        sLink.removeLast();
        sLink.del(1);
        sLink.printLink();
        System.out.println(sLink.size());

对于单链表来讲,这里用了新建了两个节点first和last指向链表头部和尾部,方便获取和删除头部和尾部的值,然后这里需要注意的是,每次添加删除都要考虑到size大小,first、last的指向是否需要改变,插入节点的时候一定要注意插入点和插入点两旁点的指向关系要修改,删除节点的时候也是一样。

3、java实现双向链表(可存储任意类型)

代码如下:

class Dlink<T> implements Link<T>{
    private int size = 0;
    private Node<T> first;
    private Node<T> last;
    private static class Node<T>{
        T item;
        Node<T> next;
        Node<T> prev;
        public Node(Node<T> prev,T item,Node<T> next) {
            // TODO Auto-generated constructor stub
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }
    @Override
    public void addFirst(T item) {
        Node<T> newnNode = new Node<>(null, item, first);
        if (first == null) {
            first = newnNode;
            last = newnNode;
        }else{
            first.prev = newnNode;
            first = newnNode;
        }
        size++;
    }

    @Override
    public void addLast(T item) {
        Node<T> newnNode = new Node<>(last, item, null);
        if (last == null) {
            first = newnNode;
            last = newnNode;
        }else{
            last.next = newnNode;
            last = newnNode;
        }
        size++;
    }

    @Override
    public T getFisrt() {
        chechIndex(0);
        return first.item;
    }

    @Override
    public T getLast() {
        chechIndex(0);
        return last.item;
    }

    @Override
    public T get(int index) {
        chechIndex(index);
        if(index<(size>>1)){
            Node<T> node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            return node.item;
        }else {
            Node<T> node = last;
            for (int i = size-1; i > index; i--) {
                node = node.prev;
            }
            return node.item;
        }
    }

    @Override
    public void set(int index, T item) {
        chechIndex(index);
        if(index<(size>>1)){
            Node<T> node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            node.item = item;
        }else {
            Node<T> node = last;
            for (int i = size-1; i > index; i--) {
                node = node.prev;
            }
            node.item = item;
        }
    }

    @Override
    public void insert(int index, T item) {
        checkPosition(index);
        Node<T> newnNode = new Node<T>(null, item, null);
        Node<T> node = first;
        if (index == 0) {
            addFirst(item);
        }else if (index == size) {
            addLast(item);
        }
        else {
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            //将新插入的点前后指向索引两边的点
            newnNode.prev = node.prev;
            newnNode.next = node;
            //索引两边的点指向这个插入点
            node.prev.next = newnNode;
            node.prev = newnNode;
            size++;
        }
    }

    @Override
    public T del(int index) {
        chechIndex(index);
        Node<T> node = first;
        Node<T> cunNode = null;
        T item = null;
        if (index == 0) {
            removeFirst();
        }else if (index == size-1) {
            removeLast();
        }else {
            for (int i = 0; i <= index; i++) {
                if (i == index-1) {
                    cunNode = node;
                }
                if (i == index) {
                    item = node.item;
                }
                node = node.next;
            }
            cunNode.next = node;
            node.prev = cunNode;
            size--;
        }
        return item;
    }

    @Override
    public T removeFirst() {
        chechIndex(0);
        T item = first.item;
        first = first.next;
        if (first == null) {
            last = null;
        }else {
            first.prev = null;
        }
        size--;
        return item;
    }

    @Override
    public T removeLast() {
        chechIndex(0);
        T item = last.item;
        last = last.prev;
        if (last == null) {
            first = null;
        }else {
            last.next = null;
        }
        size--;
        return item;
    }

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

    @Override
    public boolean isNull() {
        return size == 0;
    }

    @Override
    public void printLink() {
        chechIndex(0);
        Node<T> node = first;
        while(node != null){
            System.out.print(node.item);
            node = node.next;
        }
        System.out.println();
    }

    @Override
    public boolean chechIndex(int index) {
        return index<size&&index>=0;
    }

    @Override
    public boolean checkPosition(int index) {
        // TODO Auto-generated method stub
        return index<=size&&index>=0;
    }

}

操作示例:

        Dlink<Integer> dlink = new Dlink<>();
        dlink.addFirst(1);
        dlink.addFirst(2);
        dlink.addFirst(3);
        dlink.addFirst(4);
        dlink.insert(1, 1);
        dlink.addLast(5);
        dlink.removeFirst();
        dlink.removeLast();
        dlink.removeLast();
        dlink.removeLast();
        dlink.del(1);
        dlink.del(0);
        dlink.insert(0, 1);
        dlink.insert(1, 1);
        dlink.insert(1, 2);
        dlink.del(1);
        dlink.set(1, 8);
        dlink.printLink();
        System.out.println(dlink.get(0));
        System.out.println(dlink.size());

对于双链表,这里也新建了两个节点first和last指向头部和尾部,不仅可以方便的获取和删掉尾部的值,因为是双向的查找节点的时候可以根据索引的值从前面查找或者从后面开始查找,添加和删除节点的时候也要注意索引点两边节点的指向关系要修正。

4、对比

双向列表查找的时候更有效率,不仅可以从前往后找还可以从后往前找。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值