代码改变世界

双向循环链表实践

2017-08-14 16:22  猪牙哥  阅读(235)  评论(0编辑  收藏  举报

题目:

  要求实现用户输入一个数使得26个字母的排列发生变化,例如用户输入3,输出结果:

  DEFGHIJKLMNOPQRSTUVWXYZABC

  同时需要支持负数,例如用户输入-3,输出结果:

  XYZABCDEFGHIJKLMNOPQRSTUVW

-----------------------------------------------------------------------------------------------------------------------------

首先,我们要明白什么叫双向循环链表,双向,也就是有pre和next,循环也就是首尾相连,那么我们把双向循环链表设计成这样

public class MyLoopLinkedList<E> {
    private Node<E> head;

    public MyLoopLinkedList() {
        super();
    }

    /**
     * 添加元素,默认添加到尾部
     * 
     * @param e
     */
    public void add(E e) {
        if (head == null) {
            head = new Node<E>(null, e, null);
        } else {// 将首尾相连
            Node<E> n = new Node<E>(null, e, null);
            if (head.pre == null) {//
                head.pre = n;
                head.next = n;
                n.next = head;
                n.pre = head;
            } else {
                Node<E> last = head.pre;
                last.next = n;
                n.pre = last;
                n.next = head;
                head.pre = n;
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[").append(head.item).append(",");
        for (Node<E> n = head.next; head.next != null && n != head; n = n.next) {
            sb.append(n.item).append(",");
        }
        sb.deleteCharAt(sb.length() - 1).append("]");
        return sb.toString();
    }

    private static class Node<E> {
        E item;
        Node<E> pre;
        Node<E> next;

        Node(Node<E> pre, E element, Node<E> next) {
            this.pre = pre;
            this.item = element;
            this.next = next;
        }
    }
}

这里我把第一个添加的元素作为头部,测试一下是否符合可以

    public static void main(String[] args){
        MyLoopLinkedList<String> list=new MyLoopLinkedList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");
        list.add("F");
        list.add("G");
        list.add("H");
        list.add("I");
        list.add("J");
        list.add("K");
        list.add("L");
        list.add("M");
        list.add("N");
        list.add("O");
        list.add("P");
        list.add("Q");
        list.add("R");
        list.add("S");
        list.add("T");
        list.add("U");
        list.add("V");
        list.add("W");
        list.add("X");
        list.add("Y");
        list.add("Z");
        System.out.println(list.toString());
    }

输出结果:

ok,没问题,那么回到正题,要求输入一个3,就从第三个数开始读起,并且支持负数,那么我个人想到了两个解决方案

①直接改变头部,代码如下

/**
     * 更变头部
     * 
     * @param position
     */
    public void changeHead(int position) {
        for (int i = 0; i < Math.abs(position); i++) {
            if (position > 0) {
                head = head.next;
            } else {
                head = head.pre;
            }
        }
    }

将上面的代码添加到MyLoopLinkedList.java里面

测试代码

public static void main(String[] args){
        MyLoopLinkedList<String> list=new MyLoopLinkedList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");
        list.add("F");
        list.add("G");
        list.add("H");
        list.add("I");
        list.add("J");
        list.add("K");
        list.add("L");
        list.add("M");
        list.add("N");
        list.add("O");
        list.add("P");
        list.add("Q");
        list.add("R");
        list.add("S");
        list.add("T");
        list.add("U");
        list.add("V");
        list.add("W");
        list.add("X");
        list.add("Y");
        list.add("Z");
        System.out.println(list.toString());
        list.changeHead(3);
        System.out.println(list.toString());
    }

测试结果:

②添加一个成员变量,设置读取的初始位置,修改toString方法

private int readLocation = 0;//读取位置

    public void setReadLocation(int readLocation) {
        this.readLocation = readLocation;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        Node<E> readNode = getReadNode();
        sb.append("[").append(readNode.item).append(",");
        for (Node<E> n = readNode.next; readNode.next != null && n != readNode; n = n.next) {
            sb.append(n.item).append(",");
        }
        sb.deleteCharAt(sb.length() - 1).append("]");
        return sb.toString();
    }
    /**
     * 确定读取元素位置
     * @return
     */
    private Node<E> getReadNode() {
        Node<E> readNode = head;
        for (int i = 0; i < Math.abs(readLocation); i++) {
            if (readLocation > 0) {
                readNode = readNode.next;
            } else if (readLocation < 0) {
                readNode = readNode.pre;
            }
        }
        return readNode;
    }

测试代码

public static void main(String[] args){
        MyLoopLinkedList<String> list=new MyLoopLinkedList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");
        list.add("F");
        list.add("G");
        list.add("H");
        list.add("I");
        list.add("J");
        list.add("K");
        list.add("L");
        list.add("M");
        list.add("N");
        list.add("O");
        list.add("P");
        list.add("Q");
        list.add("R");
        list.add("S");
        list.add("T");
        list.add("U");
        list.add("V");
        list.add("W");
        list.add("X");
        list.add("Y");
        list.add("Z");
        System.out.println(list.toString());
        list.setReadLocation(-3);
        System.out.println(list.toString());
    }

测试结果:

总结:两种方法我比较推荐使用第二种方法,第一种方法会导致第一次添加元素的信息掉额失,而第二种方法并没有动head成员变量,并且没有影响之前的使用