Java —— 链表

数组是一个定长的线性结构。一旦我们的内容不足或者内容过多,都有可能造成空间浪费。可以采用火车车厢的设计模式,动态进行车厢的挂载,这就好比链表。

  • 链表时间复杂度: 插入删除  O(1)   随机访问O(n)
  • 数组时间复杂度: 插入删除  O(n)   随机访问O(1)

1.链表基本结构:

每一个火车车厢(Node)都有一个节点和一个指向下一节点的地址

代码示例:

public class TestNode {
    public static void main(String[] args) {
        //封装节点
        Node head = new Node("火车头");
        Node first = new Node("车厢一");
        Node second = new Node("车厢二");
        Node last = new Node("火车尾");

        //设置车厢关系,即挂载 
        head.setNext(first);
        first.setNext(second);
        second.setNext(last);

        printLink(head);
    }
    public static void printLink(Node node ){
        if(node != null){
            System.out.println(node.getData());
            //将当前节点指向下一节点
            node = node.getNext();
            printLink(node);
        }
    }
}

//定义车厢节点(结构)
public class Node {
    //节点中数据
    private Object data;
    //指向下一个(车厢)节点的地址 -> 类型是Node
    private Node next;

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

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

2.链表实现结构

  • 存在问题:客户端需要自己来进行节点的创建以及关心的配置。所以链表还需要一个单独的Link类。

Node:负责节点内容的设置,真实保存内容。

Link:实现Node节点之间的动态挂载(将节点关联起来),为用户所用(添加数据)。

代码示例:

package com.qqy.ds.linkedlist;

/**
 * Author:qqy
 */
public interface ILink {
    /**
     * 链表增加节点操作
     *
     * @param data 节点内容    
     * @return
     */
    boolean add(Object data);

    /**
     * 判断指定内容节点在链表中是否存在    
     *
     * @param data 要判断的内容    
     * @return 返回找到的节点索引    
     */
    int contains(Object data);

    /**
     * 删除指定内容节点  
     *
     * @param data    
     * @return    
     */
    boolean remove(Object data);

    /**
     * 根据指定下标修改节点内容  
     *  
     *
     * @param index   索引下标    
     * @param newData 替换后的内容    
     * @return 替换之前的节点内容    
     */
    Object set(int index, Object newData);

    /**
     * 根据指定下标返回节点内容  
     *  
     *
     * @param index    
     * @return    
     */
    Object get(int index);

    /**
     * 链表清空    
     */
    void clear();

    /**
     * 链表的遍历需要递归实现将链表转为数组    
     *
     * @return 返回所有节点内容    
     */
    Object[] toArray();

    /**
     * 链表长度    
     *
     * @return    
     */
    int size();

    /**
     * 遍历链表    
     */
    void printLink();
}

class LinkImpl implements ILink {
    private Node1 head;  //头指针
    private Node1 last;  //尾指针
    private int size;   //链表长度

    //将Node1作为内部类原因
    //1.封装,只有LinkImpl需要用到
    //2.方便操作,无需getter、setter
    //真正的节点,负责数据存储
    public class Node1 {
        private Node1 prev;
        private Object data;
        private Node1 next;

        //作为内部类,无需定义getter、setter属性
        public Node1(Node1 prev, Object data, Node1 next) {
            this.prev = prev;
            this.data = data;
            this.next = next;
        }
    }

    @Override
    public boolean add(Object data) {
        Node1 temp = this.last;
        Node1 newNode = new Node1(temp, data, null);
        this.last = newNode;
        if (this.head == null) {
            this.head = newNode;
        } else {
            temp.next = newNode;
        }
        this.size++;

        return false;
    }

    @Override
    public int contains(Object data) {
        //null
        if (data == null) {
            int i = 0;
            for (Node1 temp = this.head; temp != null; temp = temp.next) {
                if (temp.data == null) {
                    return i;
                }
                i++;
            }
        } else {
            int i = 0;
            for (Node1 temp = this.head; temp != null; temp = temp.next) {
                if (temp.data.equals(data)) {
                    return i;
                }
                i++;
            }
        }
        return -1;
    }

    @Override
    public boolean remove(Object data) {
        if (data == null) {
            for (Node1 temp = this.head; temp != null; temp = temp.next) {
                if (temp.data == null) {
                    unLink(temp);
                    return true;
                }
            }
        } else {
            for (Node1 temp = this.head; temp != null; temp = temp.next) {
                if (temp.data.equals(data)) {
                    unLink(temp);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Object set(int index, Object newData) {
        if (!isLinkIndex(index)) {
            return null;
        }
        Node1 node = node(index);
        Object elementData = node.data;
        node.data = newData;
        return elementData;
    }

    @Override
    public Object get(int index) {
        if (!isLinkIndex(index)) {
            return null;
        }
        return node(index).data;
    }

    @Override
    public void clear() {
        for (Node1 temp = head; temp != null; ) {
            temp.data = null;
            Node1 node = temp.next;
            temp = temp.prev = temp.next = null;
            temp = node;
            this.size--;
        }
        //this.head=0;
        //this.size=0;
    }

    @Override
    public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        for (Node1 temp = head; temp != null; temp = temp.next) {
            result[i++] = temp.data;
        }
        return result;
    }

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

    @Override
    public void printLink() {
        Object[] data = this.toArray();
        for (Object temp : data) {
            System.out.println(temp);
        }
    }

    //仅供本类方法使用,根据指定的索引确定具体的节点
    private Node1 node(int index) {
        if (index < (size >> 1)) {
            Node1 temp = this.head;
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
            return temp;
        }
        Node1 temp = this.last;
        for (int i = size - 1; i > index; i--) {
            temp = temp.prev;
        }
        return temp;
    }

    //判断指定的索引是否合法
    private boolean isLinkIndex(int index) {
        return index >= 0 && index < size;
    }

    private Object unLink(Node1 x) {
        Object elementData = x.data;
        Node1 prev = x.prev;
        Node1 next = x.next;
        if (prev == null) {
            this.head = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
        if (next == null) {
            this.last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
        x.data = null;
        this.size--;
        return elementData;
    }
}
public class TestNode1 {
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("火车头");
        link.add("车厢一");
        link.add("车厢二");
        link.add("火车尾");
        System.out.println(link.contains("车厢二"));  //2
        System.out.println(link.contains("车厢三"));  //-1
//        link.clear();
        System.out.println(link.size());
        System.out.println(link.get(3));  //火车尾
        System.out.println(link.set(2,"滴滴滴"));  //车厢二
        link.printLink();
        System.out.println(link.remove("滴滴滴"));
        link.printLink();

    }
}

 

猜你喜欢

转载自blog.csdn.net/qq_42142477/article/details/84580404
今日推荐