数据结构示例代码

数据结构示例代码

准备

public class Const {
    public static final String BASE_PATH = "存放文件路径";
    public static final String DELIMITER = ">>>>>>o(=•ェ•=)m<<<<<<";
}
// 如需性能测试则直接继承
public class Efficiency {
    private long start;

    @BeforeEach
    public void before() {
        start = System.currentTimeMillis();
    }

    @AfterEach
    public void after() {
        System.out.println("用时:" + (System.currentTimeMillis() - start) + "ms");
    }
}

稀疏数组和队列

队列

public class ArrayQueue {
    /**
     * 表示数组地最大容量
     */
    private final int maxSize;

    /**
     * 队列头
     */
    private int front;

    /**
     * 队列尾
     */
    private int rear;

    /**
     * 该数组用于存放数据,模拟队列
     */
    private final int[] arr;

    public ArrayQueue(int maxSize) {
        this.maxSize = maxSize + 1;
        this.arr = new int[this.maxSize];
        front = 0;
        rear = 0;
    }


    public boolean isFull() {
        return (rear + 1) % maxSize == front;
    }

    public boolean isEmpty() {
        return front == rear;
    }

    public void addQueue(int n) {
        if (isFull()) {
            throw new RuntimeException("队列已满,无法添加数据");
        }
        arr[rear] = n;
        rear = (rear + 1) % maxSize;
    }

    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,无法取出数据");
        }
        int val = arr[front];
        front = (front + 1) % maxSize;
        return val;
    }

    public void showQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空,无数据~");
        }
        if (front < rear) {
            for (int i = front; i < rear; i++) {
                System.out.println("arr[" + i + "]=" + arr[i]);
            }
        } else {
            for (int i = front; i < maxSize; i++) {
                System.out.println("arr[" + i + "]=" + arr[i]);
            }
            for (int i = 0; i < rear; i++) {
                System.out.println("arr[" + i + "]=" + arr[i]);
            }
        }
    }

    public int headQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列空,无法取出数据");
        }
        return arr[front];
    }

    public int size() {
        if (front <= rear) {
            return rear - front;
        } else {
            return maxSize - front + rear;
        }
    }
}
public class ArrayQueueDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入队列大小:");
        int val = scanner.nextInt();
        ArrayQueue arrayQueue = new ArrayQueue(val);
        System.out.println("s(show):显示队列");
        System.out.println("e(exit):退出程序");
        System.out.println("a(add):添加数据到队列");
        System.out.println("g(get):从队列取出数据");
        System.out.println("h(head):查看队列头的数据");
        // 接收用户输入
        char key = ' ';
        boolean loop = true;
        // 输出一个菜单
        while (loop) {
            System.out.println("请输入操作:");
            key = scanner.next().charAt(0);
            switch (key) {
                case 's':
                    try {
                        arrayQueue.showQueue();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'a':
                    System.out.println("请输入一个数字:");
                    try {
                        val = scanner.nextInt();
                        arrayQueue.addQueue(val);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'g':
                    try {
                        System.out.println(arrayQueue.getQueue());
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        System.out.println(arrayQueue.headQueue());
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    loop = false;
                    break;
                default:
                    System.out.println("请输入正确的命令~");
                    break;
            }
        }
        System.out.println("程序退出~");
    }
}

稀疏数组

public class SparseArray {
    public static void main(String[] args) {
        // 创建一个原始的二维数组 11 * 11
        // 0 表示没有棋子。1表示黑子,2表示蓝子
        int[][] chessArr = new int[11][11];
        chessArr[1][2] = 1;
        chessArr[2][3] = 2;
        chessArr[4][5] = 2;
        // 输出原始二维数组
        print(chessArr);
        System.out.println("===");
        int[][] sparseArr = chess2sparse(chessArr);
        print(sparseArr);
        System.out.println("===");
        chessArr = sparse2chess(sparseArr);
        print(chessArr);
    }

    private static int[][] sparse2chess(int[][] sparseArr) {
        int[][] chessArr = new int[sparseArr[0][0]][sparseArr[0][1]];
        for (int i = 1; i <= sparseArr[0][2]; i++) {
            chessArr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }
        return chessArr;
    }

    private static int[][] chess2sparse(int[][] chessArr) {
        int row = chessArr.length;
        int col = chessArr[0].length;
        int count = 0;
        for (int[] ints : chessArr) {
            for (int j = 0; j < col; j++) {
                if (ints[j] != 0) {
                    count++;
                }
            }
        }
        int[][] sparseArr = new int[count + 1][3];
        sparseArr[0][0] = row;
        sparseArr[0][1] = col;
        sparseArr[0][2] = count;
        count = 0;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (chessArr[i][j] != 0) {
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr[i][j];
                }
            }
        }
        return sparseArr;
    }

    private static void print(int[][] array) {
        for (int[] row : array) {
            for (int data : row) {
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }
}

链表

@Data
@NoArgsConstructor
public class HeroNode {
    private int no;
    private String name;
    private String nikeName;
    private HeroNode next;

    public HeroNode(int no, String name, String nikeName) {
        this.no = no;
        this.name = name;
        this.nikeName = nikeName;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nikeName='" + nikeName + '\'' +
                '}';
    }
}
@Data
@NoArgsConstructor
public class HeroNode2 {
    private int no;
    private String name;
    private String nikeName;
    /**
     * 指向下一个节点,默认是null
     */
    private HeroNode2 next;
    /**
     * 指向前一个节点,默认是null
     */
    private HeroNode2 pre;


    public HeroNode2(int no, String name, String nikeName) {
        this.no = no;
        this.name = name;
        this.nikeName = nikeName;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nikeName='" + nikeName + '\'' +
                '}';
    }
}
public class HeroNodeDemo {
    public static void main(String[] args) {
        HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
        // 创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        // 添加
        singleLinkedList.add(hero1).add(hero4).add(hero2).add(hero3).list();
        System.out.println(Const.DELIMITER);
        // 删除
        singleLinkedList.del(2).list();
        System.out.println(Const.DELIMITER);
        hero4 = new HeroNode(4, "林冲冲", "豹子头");
        // 修改
        singleLinkedList.update(hero4).list();
        System.out.println(Const.DELIMITER);
        // 循序添加
        singleLinkedList.addByOrder(hero2).list();
    }
}

单链表

public class SingleLinkedList {
    /**
     * 初始化一个头节点,头节点不要动,不存放具体的数据
     */
    private final HeroNode head = new HeroNode(0, "", "");

    /**
     * 添加节点到单链表
     * 不考虑英雄编号顺序
     */
    public SingleLinkedList add(HeroNode node) {
        HeroNode temp = head;
        while (true) {
            // 找到链表最后
            if (temp.getNext() == null) {
                temp.setNext(node);
                break;
            }
            // 没有找到最后,将temp后移
            temp = temp.getNext();
        }
        return this;
    }

    /**
     * 添加节点到单链表
     * 考虑英雄编号顺序
     */
    public SingleLinkedList addByOrder(HeroNode node) {
        int no = node.getNo();
        HeroNode temp = head;
        while (true) {
            // 找到链表最后
            if (temp.getNext() == null) {
                temp.setNext(node);
                break;
            }
            if (temp.getNo() == no) {
                System.out.println("已存在");
                break;
            }
            if (temp.getNext().getNo() > no) {
                node.setNext(temp.getNext());
                temp.setNext(node);
                break;
            }
            // 没有找到最后,将temp后移
            temp = temp.getNext();
        }
        return this;
    }

    /**
     * 添加节点到单链表
     * 考虑英雄编号顺序
     */
    public SingleLinkedList update(HeroNode node) {
        int no = node.getNo();
        HeroNode temp = head;
        while (true) {
            // 找到链表最后
            if (temp.getNext() == null) {
                break;
            }
            if (temp.getNext().getNo() == no) {
                node.setNext(temp.getNext().getNext());
                temp.setNext(node);
                break;
            }
            // 没有找到最后,将temp后移
            temp = temp.getNext();
        }
        return this;
    }

    /**
     * 添加节点到单链表
     * 考虑英雄编号顺序
     */
    public SingleLinkedList del(int no) {
        HeroNode temp = head;
        while (true) {
            // 找到链表最后
            if (temp.getNext() == null) {
                break;
            }
            if (temp.getNext().getNo() == no) {
                temp.setNext(temp.getNext().getNext());
                break;
            }
            // 没有找到最后,将temp后移
            temp = temp.getNext();
        }
        return this;
    }

    public void list() {
        HeroNode temp = head;
        while (temp.getNext() != null) {
            System.out.println(temp.getNext());
            temp = temp.getNext();
        }
    }

    public HeroNode getHead() {
        return head;
    }
}
public class SubjectTest extends Efficiency {
    private HeroNode heroNode;

    @Test
    public void test1() {
        init();
        System.out.println(getLength(heroNode));
        System.out.println(findLastIndexNode(heroNode, 2));
        System.out.println(Const.DELIMITER);
        list(reverseList(this.heroNode));
        System.out.println(Const.DELIMITER);
        list(reverseList2(this.heroNode));
        System.out.println(Const.DELIMITER);
        stackPrint(heroNode);
    }

    public void stackPrint(HeroNode heroNode) {
        Stack<HeroNode> heroNodes = new Stack<>();
        HeroNode temp = heroNode;
        while (temp != null) {
            heroNodes.push(new HeroNode(temp.getNo(), temp.getName(), temp.getNikeName()));
            temp = temp.getNext();
        }
        while (!heroNodes.isEmpty()) {
            System.out.println(heroNodes.pop());
        }
    }

    public HeroNode reverseList(HeroNode heroNode) {
        if (heroNode == null) {
            return null;
        }
        HeroNode temp = heroNode;
        HeroNode reverseNode = new HeroNode(0, "", "");
        while (temp.getNext() != null) {
            temp = temp.getNext();
            HeroNode next = new HeroNode(temp.getNo(), temp.getName(), temp.getNikeName());
            next.setNext(reverseNode);
            reverseNode = next;
        }
        return reverseNode;
    }

    public HeroNode reverseList2(HeroNode heroNode) {
        if (heroNode == null) {
            return null;
        }
        HeroNode cur = heroNode.getNext();
        HeroNode next = null;
        HeroNode reverseNode = new HeroNode(0, "", "");
        while (cur != null) {
            // 先暂时保存当前节点的下一个节点,因为后面需要使用
            next = cur.getNext();
            // 将 cur 的下一个节点指向新链表的最前端
            cur.setNext(reverseNode.getNext());
            // 将 cur 连接到新的链表上
            reverseNode.setNext(cur);
            cur = next;
        }
        return reverseNode.getNext();
    }

    public HeroNode findLastIndexNode(HeroNode heroNode, int index) {
        if (heroNode == null || index <= 0) {
            return null;
        }
        int len = getLength(heroNode);
        if (index > len) {
            return null;
        }
        HeroNode temp = heroNode.getNext();
        for (int i = 0; i < len - index; i++) {
            temp = temp.getNext();
        }
        return temp;
    }

    public int getLength(HeroNode heroNode) {
        int len = 0;
        if (heroNode != null) {
            HeroNode temp = heroNode;
            while (temp.getNext() != null) {
                len++;
                temp = temp.getNext();
            }
        }
        return len;
    }

    public void list(HeroNode heroNode) {
        HeroNode temp = heroNode;
        while (temp != null) {
            System.out.println(temp);
            temp = temp.getNext();
        }
    }

    public void init() {
        HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
        // 创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        // 添加
        singleLinkedList.add(hero1).add(hero2).add(hero3).add(hero4);
        heroNode = singleLinkedList.getHead();
    }

}

双链表

public class DoubleLinkedList {
    /**
     * 初始化一个头节点,头节点不要动,不存放具体的数据
     */
    private final HeroNode2 head = new HeroNode2(0, "", "");

    /**
     * 返回头节点
     */
    public HeroNode2 getHead() {
        return head;
    }

    public void list() {
        HeroNode2 tmp = head.getNext();
        while (tmp != null) {
            System.out.println(tmp);
            tmp = tmp.getNext();
        }
    }

    public DoubleLinkedList add(HeroNode2 heroNode) {
        HeroNode2 tmp = head;
        while (true) {
            if (tmp.getNext() == null) {
                tmp.setNext(heroNode);
                heroNode.setPre(tmp);
                break;
            }
            tmp = tmp.getNext();
        }
        return this;
    }

    public DoubleLinkedList update(HeroNode2 heroNode) {
        HeroNode2 tmp = head.getNext();
        while (true) {
            if (tmp == null) {
                break;
            }
            if (tmp.getNo() == heroNode.getNo()) {
                tmp.setName(heroNode.getName());
                tmp.setNikeName(heroNode.getNikeName());
                break;
            }
            tmp = tmp.getNext();
        }
        return this;
    }

    public DoubleLinkedList del(int no) {
        HeroNode2 tmp = head.getNext();
        while (true) {
            if (tmp == null) {
                break;
            }
            if (tmp.getNo() == no) {
                HeroNode2 pre = tmp.getPre();
                HeroNode2 next = tmp.getNext();
                pre.setNext(next);
                if (next != null) {
                    next.setPre(pre);
                }
                break;
            }
            tmp = tmp.getNext();
        }
        return this;
    }
}
public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");
        HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
        HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");
        HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        // 增加
        doubleLinkedList.add(hero1).add(hero2).add(hero3).add(hero4).list();
        System.out.println(Const.DELIMITER);
        // 改
        hero4 = new HeroNode2(4, "林冲冲", "豹子头");
        doubleLinkedList.update(hero4).list();
        System.out.println(Const.DELIMITER);
        // 删
        doubleLinkedList.del(2).list();
        System.out.println(Const.DELIMITER);
        // 添
        hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
        doubleLinkedList.add(hero2).list();
    }
}

Josephu 问题

public class JosepFu {
    public static void main(String[] args) {
        // CircleSingleLinkedListDemo
        // TODO: do some thing...
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Body {
    private int no;
    private Body next;

    public Body(int no) {
        this.no = no;
    }

    @Override
    public String toString() {
        return "Body{" +
                "no=" + no +
                '}';
    }
}
public class CircleSingleLinkedList {
    // 创建第一个节点,当前没有编号
    private Body first = null;

    public CircleSingleLinkedList addBody(int num) {
        if (first == null) {
            first = new Body(num);
            first.setNext(first);
            return this;
        }
        Body next = first;
        while (true) {
            if (next.getNext() == first) {
                next.setNext(new Body(num));
                next.getNext().setNext(first);
                break;
            }
            next = next.getNext();
        }
        return this;
    }

    public void showBody() {
        if (first != null) {
            Body tmp = first;
            while (true) {
                System.out.println(tmp);
                if (tmp.getNext() == first) {
                    break;
                }
                tmp = tmp.getNext();
            }
        }
    }

    public int size() {
        int i = 0;
        if (first != null) {
            Body tmp = first;
            while (true) {
                ++i;
                if (tmp.getNext() == first) {
                    break;
                }
                tmp = tmp.getNext();
            }
        }
        return i;
    }

    /**
     * 计算出圈顺序
     *
     * @param startNo  表示从第几个小孩开始数数
     * @param countNum 表示数几下
     */
    public List<Integer> countBody(int startNo, int countNum) {
        int nums = size();
        if (first == null || startNo < 1 || startNo > nums || countNum < 1) {
            return null;
        }
        Body tmp = first;
        for (int i = 1; i < startNo; i++) {
            tmp = tmp.getNext();
        }
        ArrayList<Integer> order = new ArrayList<>();
        if (countNum == 1) {
            Body start = tmp;
            while (true) {
                order.add(tmp.getNo());
                if (tmp.getNext() == start) {
                    return order;
                }
                tmp = tmp.getNext();
            }
        }
        int i = 1;
        while (true) {
            if (tmp.getNext() == tmp) {
                order.add(tmp.getNo());
                break;
            }
            ++i;
            if (i == countNum) {
                i = 1;
                order.add(tmp.getNext().getNo());
                tmp.setNext(tmp.getNext().getNext());
            }
            tmp = tmp.getNext();
        }
        return order;
    }
}
public class CircleSingleLinkedListDemo {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBody(1).addBody(2).addBody(3).addBody(4).addBody(5).showBody();
        System.out.println(circleSingleLinkedList.countBody(5, 5));
    }
}

public class ArrayStack {
    @Getter
    private final int maxSize;
    private int[] stack;
    @Getter
    private int top = -1;

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[maxSize];
    }

    public boolean isFull() {
        return top == maxSize - 1;
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public void push(int val) {
        if (isFull()) {
            throw new RuntimeException("栈满");
        }
        stack[++top] = val;
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        return stack[top--];
    }

    public void list() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        for (int i = top; i >= 0; i--) {
            System.out.println("stack[" + i + "] = " + stack[i]);
        }
    }
}
public class ArrayStack2 {
    @Getter
    private final int maxSize;
    private int[] stack;
    @Getter
    private int top = -1;

    public ArrayStack2(int maxSize) {
        this.maxSize = maxSize;
        this.stack = new int[maxSize];
    }

    public boolean isFull() {
        return top == maxSize - 1;
    }

    public boolean isEmpty() {
        return top == -1;
    }

    public void push(int val) {
        if (isFull()) {
            throw new RuntimeException("栈满");
        }
        stack[++top] = val;
    }

    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        return stack[top--];
    }

    public int peek() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        return stack[top];
    }

    public void list() {
        if (isEmpty()) {
            return;
        }
        for (int i = top; i >= 0; i--) {
            System.out.println("stack[" + i + "] = " + stack[i]);
        }
    }
    public int priority(char operator) {
        if (operator == '*' || operator == '/') {
            return 1;
        }
        if (operator == '+' || operator == '-') {
            return 0;
        }
        return -1;
    }

    public boolean isOperator(char val) {
        return val == '+' || val == '-' || val == '*' || val == '/';
    }

    public int cal(int val1, int val2, char operator) {
        int res = 0;
        switch (operator) {
            case '+':
                res = val1 + val2;
                break;
            case '-':
                res = val2 - val1;
                break;
            case '*':
                res = val1 * val2;
                break;
            case '/':
                res = val2 / val1;
                break;
            default:
                break;
        }
        return res;
    }
}
public class ArrayStackDemo {
    public static void main(String[] args) {
        boolean loop = true;
        System.out.println("请输入栈大小");
        Scanner scanner = new Scanner(System.in);
        String key = "";
        int val = scanner.nextInt();
        ArrayStack stack = new ArrayStack(val);
        System.out.println("show:显示栈");
        System.out.println("exit:退出程序");
        System.out.println("push:入栈");
        System.out.println("pop:出栈");
        while (loop) {
            key = scanner.next();
            switch (key) {
                case "show":
                    try {
                        stack.list();
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "push":
                    System.out.println("请输入要入栈的值");
                    val = scanner.nextInt();
                    try {
                        stack.push(val);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "pop":
                    try {
                        System.out.println(stack.pop());
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    System.out.println("退出~");
                    loop = false;
                    break;
                default:
                    System.out.println("请输入正确的命令");
                    break;
            }
        }
        System.out.println("退出~");
    }
}

简易计算器

public class Calculator {
    public static void main(String[] args) {
        // String expression = "7 * 2 * 2 - 5 + 1 - 5 + 3 - 4";
        String expression = "7 * 2 * 12 - 5 + 1 - 5 + 13 - 14";
        expression = expression.replace(" ", "");
        // 数字栈 符合栈
        int length = expression.length();
        if (length == 0) {
            System.out.println(0);
            return;
        }
        if (length == 1) {
            System.out.println(expression);
            return;
        }
        int num1, num2, res;
        char operator;
        int len = length / 2;
        boolean flag = false;
        ArrayStack2 numStack = new ArrayStack2(len + 1);
        ArrayStack2 operatorStack = new ArrayStack2(len);
        for (char val : expression.toCharArray()) {
            if (operatorStack.isOperator(val)) {
                flag = false;
                if (!operatorStack.isEmpty() && operatorStack.priority(val) <= operatorStack.priority((char) operatorStack.peek())) {
                    num1 = numStack.pop();
                    num2 = numStack.pop();
                    operator = (char) operatorStack.pop();
                    res = numStack.cal(num1, num2, operator);
                    numStack.push(res);
                    operatorStack.push(val);
                    continue;
                }
                operatorStack.push(val);
            } else {
                if (flag) {
                    numStack.push(Integer.parseInt(numStack.pop() + String.valueOf(val)));
                    continue;
                }
                flag = true;
                numStack.push(val - '0');
            }
        }
        while (!operatorStack.isEmpty()) {
            num1 = numStack.pop();
            num2 = numStack.pop();
            operator = (char) operatorStack.pop();
            res = numStack.cal(num1, num2, operator);
            numStack.push(res);
        }
        System.out.println(expression + " = " + numStack.pop());
    }
}

逆波兰表达式

public class PolandNotation {

    public static void main(String[] args) {
        // 先定义一个逆波兰表达式
        // (3 + 4) * 5 -6 => 30 4 + 5 * 6 - => 164
        // 4 * 5 - 8 + 60 + 8 / 2 => 4 5 * 8 - 60 + 8 2 / +
        // 测试
        // String suffixExpression = "3 4 + 5 * 6 -";
        String suffixExpression = "4 5 * 8 - 60 + 8 2 / +";
        // 思路
        // 1. 先将 "30 4 + 5 * 6 -" => 放到 ArrayList中
        // 2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈 完成计算
        List<String> list = getListString(suffixExpression);
        System.out.println("list = " + list);
        System.out.println("calculate(suffixExpression) = " + calculate(suffixExpression));

    }

    /**
     * 将一个逆波兰表达式,依次将数据和运算符 放入到 ArrayList 中
     *
     * @param suffixExpression 逆波兰表达式
     * @return 集合
     */
    public static List<String> getListString(String suffixExpression) {
        // 将 suffixExpression 分割
        char[] seCs = suffixExpression.replace(" ", "").toCharArray();
        ArrayList<String> list = new ArrayList<>();
        for (char seC : seCs) {
            list.add(String.valueOf(seC));
        }
        return list;
    }

    /**
     * 完成逆波兰表达式的计算
     * 1) 从左至右扫描,将 3 和 4 压入栈堆
     * 2) 遇到 + 运算符,因此弹出 4 和 3 (4 为栈顶元素, 3 为次栈顶元素),计算出 3 + 4 的值,得 7,再将 7 入栈
     * 3) 将 5 入栈
     * 4) 接下来是 * 运算符,因此弹出 5 和 7,计算出 7 * 5 = 35,将 35 入栈
     * 5) 将 6 入栈
     * 6) 最后是 - 运算符,计算出 35 - 6 的值,即 29,因此得出最终结果
     *
     * @return 结果
     */
    public static int calculate(String suffixExpression) {
        // 创建栈,只需要一个栈即可
        Stack<String> stack = new Stack<>();
        // 遍历
        String[] ses = suffixExpression.split(" ");
        for (String se : ses) {
            // 如果是数字
            if (se.matches("\\d+")) {
                // 入栈
                stack.push(se);
            } else {
                // 出栈两个数字,并运算,再入栈
                Integer num2 = Integer.parseInt(stack.pop());
                Integer num1 = Integer.parseInt(stack.pop());
                int res;
                switch (se) {
                    case "+":
                        res = num1 + num2;
                        break;
                    case "-":
                        res = num1 - num2;
                        break;
                    case "*":
                        res = num1 * num2;
                        break;
                    case "/":
                        res = num1 / num2;
                        break;
                    default:
                        throw new RuntimeException("运算符有误");
                }
                stack.push(String.valueOf(res));
            }
        }
        return Integer.parseInt(stack.pop());
    }
}

中缀转成逆波兰表达式

public class PolandNotation02 {

    public static void main(String[] args) {
        // 完成将一个中缀表达式转成后缀表达式的功能
        // 说明
        // 1 + ((2 + 3) * 4) - 5 => 转成 1 2 3 + 4 * + 5 -
        String expression = "1 + ((2 + 3) * 4) - 5";
        System.out.println(toInfixExpressionList(expression));
        System.out.println(parseSuffixExpressionList(expression));
    }

    private static List<String> parseSuffixExpressionList(String expression) {
        List<String> els = toInfixExpressionList(expression);
        // 定义两个栈
        // 符号栈
        Stack<String> s1 = new Stack<>();
        // 说明: 因为 s2 这个 栈,在整个转换过程中,没有 pop 操作,而且后面我们还需要逆序输出
        // 因此比较麻烦,这里我们就不用 Stack<String> 直接使用 List<String> s2
        // Stack<String> s2 = new Stack<String> s2 // 存储中间结果的栈 s2
        // 存储中间结果的 List s2
        List<String> s2 = new ArrayList<>();
        // 遍历 els
        for (String el : els) {
            if (el.matches("\\d+")) {
                s2.add(el);
            } else if ("(".equals(el)) {
                s1.push(el);
            } else if (")".equals(el)) {
                while (true) {
                    String symbol = s1.pop();
                    if ("(".equals(symbol)) {
                        break;
                    }
                    s2.add(symbol);
                }
            } else {
                // 比较优先级
                while (!s1.isEmpty() && priority(s1.peek()) >= priority(el)) {
                    s2.add(s1.pop());
                }
                s1.push(el);
            }
        }
        while (!s1.isEmpty()) {
            s2.add(s1.pop());
        }
        return s2;
    }

    public static List<String> toInfixExpressionList(String expression) {
        char[] chars = expression.replace(" ", "").toCharArray();
        ArrayList<String> els = new ArrayList<>();
        for (char a : chars) {
            if (a >= '0' && a <= '9') {
                int li = els.size() - 1;
                if (li >= 0) {
                    String la = els.get(li);
                    char lac = la.charAt(0);
                    if (lac >= '0' && lac <= '9') {
                        els.set(li, la + a);
                        continue;
                    }
                }
            }
            els.add(String.valueOf(a));
        }
        return els;
    }

    private static int priority(String operator) {
        if ("*".equals(operator) || "/".equals(operator)) {
            return 1;
        }
        if ("+".equals(operator) || "-".equals(operator)) {
            return 0;
        }
        return -1;
    }
}

完整计算器

public class ReversePolishMultiCalc {
    /**
     * 匹配运算符 + - * / ( ) 运算符
     */
    private static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)";

    private static final String LEFT = "(";
    private static final String RIGHT = ")";
    private static final String ADD = "+";
    private static final String MINUS = "-";
    private static final String MULTIPLY = "*";
    private static final String DIVIDE = "/";

    /**
     * 加减 + -
     */
    private static final int LEVEL_01 = 1;
    /**
     * 乘除 * /
     */
    private static final int LEVEL_02 = 2;
    /**
     * 括号
     */
    private static final int LEVEL_HIGH = Integer.MAX_VALUE;

    private static Stack<String> stack = new Stack<>();

    private static List<String> data = Collections.synchronizedList(new ArrayList<>());

    /**
     * 去除所有空格
     */
    public static String replaceAllBlank(String s) {
        // \\s+ 匹配任何空格字符,包括空格,制表符,换页符等等,等价于 [\f\n\r\t\v]
        return s.replaceAll("\\s+", "");
    }

    /**
     * 判断是不是数字
     */
    public static boolean isNumber(String s) {
        Pattern pattern = Pattern.compile("^[-|+]?[.\\d]*$");
        return pattern.matcher(s).matches();
    }

    /**
     * 判断是不是运算符
     */
    public static boolean isSymbol(String s) {
        return s.matches(SYMBOL);
    }

    /**
     * 匹配运算等级
     */
    public static int caleLevel(String s) {
        if ("+".equals(s) || "-".equals(s)) {
            return LEVEL_01;
        } else if ("*".equals(s) || "/".equals(s)) {
            return LEVEL_02;
        }
        return LEVEL_HIGH;
    }

    /**
     * 匹配
     */
    public static synchronized List<String> doMatch(String s) {
        if (Objects.isNull(s) || "".equals(s.trim())) {
            throw new RuntimeException("data is empty");
        }
        if (!isNumber(String.valueOf(s.charAt(0)))) {
            throw new RuntimeException("data illeagle, start not with a number");
        }

        s = replaceAllBlank(s);

        String each;
        int start = 0;
        for (int i = 0; i < s.length(); i++) {
            String symbol = String.valueOf(s.charAt(i));
            if (isSymbol(symbol)) {
                each = symbol;
                // 栈为空,操作符,或者 操作符优先级大于栈顶优先级 && 操作符优先级不是 () 的优先级 即是 ( 直接入栈
                if (RIGHT.equals(each)) {
                    // ) 操作符, 依次出栈入列直到栈空 或者遇到第一个 ) 操作符,此时 ) 出栈
                    while (!stack.isEmpty()) {
                        String pop = stack.pop();
                        if (LEVEL_HIGH == caleLevel(pop)) break;
                        data.add(pop);
                    }
                } else {
                    while (!stack.isEmpty() && caleLevel(each) <= caleLevel(stack.peek())) {
                        if (caleLevel(stack.peek()) == LEVEL_HIGH) break;
                        data.add(stack.pop());
                    }
                    stack.push(each);
                }
                // 前一个运算符位置
                start = i;
            } else if (i == s.length() - 1 || isSymbol(String.valueOf(s.charAt(i + 1)))) {
                // 为最后一位 或者 下一位是符号 适配多位数
                each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1);
                if (isNumber(each)) {
                    data.add(each);
                    continue;
                }
                throw new RuntimeException("data not match number");
            }
        }
        // 如果栈里还有元素,此时元素需要依次出栈入队,可以想象为战里面只剩下栈顶为 / ,栈底为 + ,应该依次出栈入列,可以直接翻转整个 stack 添加到队列
        Collections.reverse(stack);
        data.addAll(new ArrayList<>(stack));
        System.out.println(data);
        return data;
    }

    /**
     * 算出结果
     */
    public static synchronized Double doCalc(List<String> list) {
        double d = 0D;
        if (list == null || list.isEmpty()) {
            return null;
        }
        if (list.size() == 1) {
            return Double.parseDouble(list.get(0));
        }
        List<String> tmp = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            tmp.add(list.get(i));
            if (isSymbol(list.get(i))) {
                d += doTheMatch(list.get(i - 2), list.get(i - 1), list.get(i));
                tmp.remove(i);
                tmp.remove(i - 1);
                tmp.set(i - 2, String.valueOf(d));
                tmp.addAll(list.subList(i + 1, list.size()));
                break;
            }
        }
        return doCalc(tmp);
    }

    public static Double doTheMatch(String s1, String s2, String symbol) {
        Double result;
        switch (symbol) {
            case ADD:
                result = Double.parseDouble(s1) + Double.parseDouble(s2);
                break;
            case MINUS:
                result = Double.parseDouble(s1) - Double.parseDouble(s2);
                break;
            case MULTIPLY:
                result = Double.parseDouble(s1) * Double.parseDouble(s2);
                break;
            case DIVIDE:
                result = Double.parseDouble(s1) / Double.parseDouble(s2);
                break;
            default:
                result = null;
        }
        return result;
    }

    public static void main(String[] args) {
        // System.out.println(doCalc(doMatch("1 + 1")));
        // [9, 3, 1, -, 3, *, +, 10, 2, /, +]
        // System.out.println(doCalc(doMatch("9 + (3 - 1) * 3 + 10 / 2")));
        System.out.println(doCalc(doMatch("12.8 + (2 - 3.55) * 4 + 10 / 5.0")));
    }
}

递归

public class Recursion {
    public static void main(String[] args) {
        // 打印问题
        test(4);
        // 阶乘问题
        System.out.println(factorial(3));
    }

    // 打印问题
    public static void test(int n) {
        if (n > 2) {
            test(n - 1);
        } else {
            System.out.println("n = " + n);
        }
    }

    // 阶乘问题
    public static int factorial(int n) {
        if (n == 1) {
            return n;
        } else {
            return n * factorial(n - 1);
        }
    }
}

迷宫

public class MiGong {
    public static void main(String[] args) {
        // 先创建一个二维数组,模拟迷宫
        // 地图
        int[][] map = new int[8][7];
        // 使用 1 表示墙
        // 上下全部设置为 1
        for (int i = 0; i < 7; i++) {
            map[0][i] = 1;
            map[7][i] = 1;
        }
        for (int i = 0; i < 8; i++) {
            map[i][0] = 1;
            map[i][6] = 1;
        }
        // 设置挡板,1 表示
        map[3][1] = 1;
        map[3][2] = 1;
        // map[6][5] = 1;
        // map[1][2] = 1;
        // map[2][2] = 1;
        // 输出地图
        System.out.println("地图的情况");
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + "\t");
            }
            System.out.println();
        }
        // 使用递归回溯给小球找路
        System.out.println(setWay(map, 1, 1));
        // System.out.println(setWay2(map, 1, 1));

        // 输出新的地图,小球走过,并标识过的地图情况
        System.out.println("小球走过,并标识过的地图情况");
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 7; j++) {
                System.out.print(map[i][j] + "\t");
            }
            System.out.println();
        }
    }

    /**
     * 使用递归回溯给小球找路
     * 说明
     * 1. map 表示地图
     * 2. i, j 表示从地图哪个位置开始出发
     * 3. 如果小球能到 map[6][5] 位置, 则说明通路找到
     * 4. 约定:当 map[i][j] 为 0 表示该点没有走过;当为 1 表示墙;2 表示通路可以走;3 表示该点已经走过,但走不通
     * 5. 在走迷宫时需要约定一个策略(方法) 下 -> 右 -> 上 -> 左, 如果该点走不通, 再回溯
     */
    public static boolean setWay(int[][] map, int i, int j) {
        // 通路已经找到
        if (map[6][5] == 2) {
            return true;
        } else {
            // 如果当前这个点还没有走过
            if (map[i][j] == 0) {
                // 假定该点可以走通
                map[i][j] = 2;
                // 按照策略 下 -> 右 -> 上 -> 左 走
                if (setWay(map, i + 1, j)
                        || setWay(map, i, j + 1)
                        || setWay(map, i - 1, j)
                        || setWay(map, i, j - 1)) {
                    return true;
                } else {
                    // 说明该点走不通,是死路
                    map[i][j] = 3;
                    return false;
                }
            } else {
                // map[i][j] != 0, 则可能为 1, 2, 3
                return false;
            }
        }
    }

    /**
     * 修改找路策略,改为 上 -> 右 -> 下 -> 左
     */
    public static boolean setWay2(int[][] map, int i, int j) {
        // 通路已经找到
        if (map[6][5] == 2) {
            return true;
        } else {
            // 如果当前这个点还没有走过
            if (map[i][j] == 0) {
                // 假定该点可以走通
                map[i][j] = 2;
                // 按照策略 上 -> 右 -> 下 -> 左 走
                if (setWay(map, i - 1, j)
                        || setWay(map, i, j + 1)
                        || setWay(map, i + 1, j)
                        || setWay(map, i, j - 1)) {
                    return true;
                } else {
                    // 说明该点走不通,是死路
                    map[i][j] = 3;
                    return false;
                }
            } else {
                // map[i][j] != 0, 则可能为 1, 2, 3
                return false;
            }
        }
    }
}

八皇后

@SuppressWarnings("all")
public class Queue8 {
    // 定义 一个 max 表示 共有多少个皇后
    private final int MAX = 8;
    // 定义 数组 array, 保存皇后放置位置的结果,比如 arr = {0, 4, 7, 5, 2, 6, 1, 3}
    // array 下标代表第几行,即第几个皇,arr[i] = val, val 表示第 i + 1 个皇后,放在第 i + 1 行的第 val + 1 列
    private int[] array = new int[MAX];
    private int count = 0;
    private int judgeCount = 0;

    public static void main(String[] args) {
        // 测试
        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.println();
        System.out.printf("一共%d种解法%n", queue8.count);
        System.out.printf("一共判断冲突的次数%d次", queue8.judgeCount);
    }

    /**
     * 编写一个方法吗,放置第n个皇后
     * 特别注意:check 是 每一次递归时,进入到 check 中都有  for (int i = 0; i < max; i++) 因此会有回溯
     */
    private void check(int n) {
        // n = 8,其实 8 个皇后就刚好放好
        if (n == MAX) {
            count++;
            print();
            return;
        }
        // 依次放入皇后,并判断冲突
        for (int i = 0; i < MAX; i++) {
            // 先把当前这个皇后n, 放到改行的第一列
            array[n] = i;
            // 判断当前放置第 n 个皇后到 i 列时,是否冲突
            if (judge(n)) {
                // 不冲突
                // 接着放 n+1 个皇后,即开始递归
                check(n + 1);
            }
            // 如果冲突,就继续执行 array[n] = i, 即将第 n 个皇后,放置在本行的 后移的一个位置
        }
    }

    /**
     * 查看当我们放置第 n 个 皇后,就去检测皇后是否和前面已经摆放的皇后冲突
     */
    public boolean judge(int n) {
        judgeCount++;
        for (int i = 0; i < n; i++) {
            // 说明
            // 1. array[i] == array[n] 表示判断 第 n 个皇后是否和前面的 n-1 个皇后在同一列
            // 2. Math.abs(n - i) == Math.abs(array[n] - array[i]) 表示判断第 n 个皇后是否和第 i 皇后是否在同一斜线
            // n = 1 放置第 2 列  1 n = 1 array[1] = 1
            // Math.abs(1 - 0) == 1      Math.abs(array[n] - array[i]) = Math.abs(1 - 0) = 1
            // 3. 判断是否在同一行,没有必要,n 每次都在递减
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 写一个方法,可以将皇后摆放的位置输出
     */
    private void print() {
        for (int i : array) {
            System.out.print(i + "\t");
        }
        System.out.println();
    }
}

排序算法

时间复杂度

public class TimeComplexity {
    // O(1) < O(log₂n) < O(n) < O(nlog₂n) < O(n²) < O(n³) < O(n^k) < O(2^n)

    /**
     * 常熟阶 O(1)
     * 无论代码多少行 只要没有循环,代码时间复杂度就是 O(1)
     */
    public void one() {
        int i = 1;
        int j = 1;
        ++i;
        j++;
        int m = i + j;
    }

    /**
     * 对数阶 O(log₂n)
     */
    public void two(int n) {
        int i = 1;
        while (i < n) {
            i = i * 2;
        }
        // 解释:i(1) * 2 * 2... > n 后循环结束,假设 循环 x 次后,即 2 ^ x = n => x = log₂n
    }

    /**
     * 线性阶 O(n)
     */
    public void three(int n) {
        int j = 0;
        for (int i = 0; i < n; i++) {
            j += i;
            j++;
        }
        // 解释:循环 n 次
    }

    /**
     * 对线性阶 O(nlog₂n)
     */
    public void four(int n) {
        for (int i = 0; i < n; i++) {
            int j = 1;
            while (j < n) {
                j = j * 2;
            }
        }
        // 解释:将 时间复杂度为 O(log₂n) 的代码循环 n 次
    }

    /**
     * 平方阶 O(n²)
     */
    public void five(int n) {
        int k = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                k += i + j;
                k++;
            }
        }
        // 解释:将 时间复杂度为 O(n) 的 代码再嵌套循环一次
        // 如果是将外层循环 n 改为 m, 那么它的时间复杂度就为 O(m * n)
        // 立方阶 O(n³) < k次阶 (n^k) 与 平方阶 类似,即 嵌套循环 对应次
    }

    // 平均时间复杂度 ==> 可能的输入实例均以等概率出现情况下该算法的运行时间
    // 最坏时间复杂度
    // 一般讨论的时间复杂度均是最坏时间复杂度,因为可以保证任何输入实例 的运行时间都不会比最坏时间最长
    // 平均时间复杂度 和 最坏时间复杂度 是否一致与算法有关
    // 基本 排序算法 各 时间复杂度 百度图表 了解
    // 空间复杂度 自行了解
}

工具

public interface Sort {
    int[] sort(int[] arr);
}
public class SortUtil {

    public static void sortPrint(int[] arr, Sort sort) {
        System.out.println(Arrays.toString(sort.sort(arr)));
    }

    public static void print(int i, int[] arr) {
        System.out.println("第" + i + "轮后");
        System.out.println(Arrays.toString(arr));
    }

    public static void capability(Sort sort) {
        int[] arr = new int[80000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 8000000);
        }
        long start = System.currentTimeMillis();
        System.out.println(Arrays.toString(sort.sort(arr)));
        System.out.println("耗时:" + (System.currentTimeMillis() - start) + " ms");
    }

    public static void printCapability(int[] arr, Sort sort) {
        sortPrint(arr, sort);
        System.out.println(Const.DELIMITER);
        capability(sort);
    }
}

冒泡排序

public class BubbleSort implements Sort {
    public static void main(String[] args) {
        int[] arr = {3, 9, -1, 10, 20};
        SortUtil.printCapability(arr, new BubbleSort());
    }

    /**
     * 冒泡排序 时间复杂度 O(n^2)
     */
    public int[] bubbleSort(int[] arr) {
        // 临时变量
        int temp = 0;
        boolean flag = false;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1; j++) {
                // 如果前面的数比后面的大,则交换
                if (arr[j] > arr[j + 1]) {
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            // SortUtil.print(i + 1, arr);
            if (!flag) {
                // 在一趟交换中,一次交换都没有发生过
                break;
            } else {
                // 重置 flag 进行下次判断
                flag = false;
            }
        }
        return arr;
    }

    @Override
    public int[] sort(int[] arr) {
        return bubbleSort(arr);
    }
}

选择排序

public class SelectSort implements Sort {
    public static void main(String[] args) {
        int[] arr = {101, 34, 119, 1, -1, 90, 123};
        SortUtil.printCapability(arr, new SelectSort());
    }

    /**
     * 选择排序 时间复杂度 O(n^2)
     */
    public int[] selectSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length; j++) {
                // 说明假定的最小值,并不是最小值
                if (min > arr[j]) {
                    // 重置 min
                    min = arr[j];
                    // 重置 minIndex
                    minIndex = j;
                }
            }
            // 将最小值,放在 arr[i],即交换
            if (minIndex != i) {
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
            // SortUtil.print(i + 1, arr);
        }
        return arr;
    }

    @Override
    public int[] sort(int[] arr) {
        return selectSort(arr);
    }
}

插入排序

public class InsertSort implements Sort {

    public static void main(String[] args) {
        int[] arr = {101, 34, 119, 1, -1, 89};
        // SortUtil.printSort(arr, new InsertSort());
        SortUtil.printCapability(arr, new InsertSort());
    }

    /**
     * 插入排序 时间复杂度 O(n^2)
     */
    public int[] insertSort(int[] arr) {
        int insertVal;
        int insertIndex;
        for (int i = 1; i < arr.length; i++) {
            // 定义带插入的数
            insertVal = arr[i];
            // arr[i] 前面数的下标
            insertIndex = i - 1;
            // 给 insertVal 找到插入的位置
            // 说明
            // 1. insertIndex >= 0 保证在给 insertVal 找到插入位置,不越界
            // 2. insertIndex < arr[insertIndex] 待插入的数,还没有找到插入位置
            // 3. 就需要将 arr[insertIndex] 后移
            while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            // 当退出 while 循环时,说明插入的位置找到了,insertIndex + 1
            if (insertIndex + 1 != i) {
                arr[insertIndex + 1] = insertVal;
            }
            // SortUtil.print(i, arr);
        }
        return arr;
    }

    @Override
    public int[] sort(int[] arr) {
        return insertSort(arr);
    }
}

希尔排序

public class ShellSort implements Sort {
    public static void main(String[] args) {
        int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        // SortUtil.printSort(arr, new ShellSort());
        SortUtil.printCapability(arr, new ShellSort());
    }

    /**
     * 希尔排序时,对有序序列插入时采用 => 交换法
     */
    public int[] shellSort(int[] arr) {
        int temp;
        // int count = 1;
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                // 遍历组中所有的元素,共 gap 组,每组有个元素,步长为 gap
                for (int j = i - gap; j >= 0; j -= gap) {
                    // 如果当前元素大于加上步长后的那个元素,说明交换
                    if (arr[j] > arr[j + gap]) {
                        temp = arr[j];
                        arr[j] = arr[j + gap];
                        arr[j + gap] = temp;
                    }
                }
            }
            // SortUtil.print(count++, arr);
        }
        return arr;
    }

    /**
     * 希尔排序时,对有序序列插入时采用 => 移位法 时间复杂度 O(n^(1.3-2))
     */
    public int[] shellSort2(int[] arr) {
        // 增量 gap,并逐步缩小增量
        // int count = 1;
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                // 从第 gap 个元素,逐个对其中所在的组进行直接插入排序
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j - gap]) {
                    while (j - gap >= 0 && temp < arr[j - gap]) {
                        // 移动
                        arr[j] = arr[j - gap];
                        j -= gap;
                    }
                    // 当退出 while 后,就给 temp 找到插入的位置
                    arr[j] = temp;
                }
            }
            // SortUtil.print(count++, arr);
        }
        return arr;
    }

    @Override
    public int[] sort(int[] arr) {
        // 这个快太多了
        return shellSort2(arr);
        // return shellSort(arr);
    }
}

快速排序

public class QuickSort implements Sort {
    public static void main(String[] args) {
        int[] arr = {-9, 78, 0, 23, -567, 70, -1, 900, 4561};
        // SortUtil.printSort(arr, new QuickSort());
        SortUtil.printCapability(arr, new QuickSort());
    }

    /**
     * 分析:
     * 1.选定一个基准值,array[low]
     * 2.右指针从右向左遍历high--,查找比基准值小的数据,左指针从左向右low++,查找比基准值大的数据
     * 3.如果指针未相遇,交换左右两值位置,如果指针相遇,则替换基准值的位置
     * 4.左递归,右递归
     */
    public void quickSort(int[] array, int low, int high) {
        // 方法退出条件,指针相遇或错过
        if (low >= high) {
            return;
        }
        // 1. 指定基准值和左右指针记录位置
        int pivot = array[low];
        int l = low;
        int r = high;
        int temp = 0;
        // 2. 遍历条件,左右指针位置
        while (l < r) {
            // 2.1 右侧遍历
            while (l < r && array[r] >= pivot) {
                r--;
            }
            // 2.2 左侧遍历
            while (l < r && array[l] <= pivot) {
                l++;
            }
            // 2.3 l指针还在r指针右侧,尚未相遇
            if (l < r) {
                temp = array[l];
                array[l] = array[r];
                array[r] = temp;
            }
        }
        // 3. 当左右指针相遇,交换基准值位置
        array[low] = array[l];
        array[l] = pivot;
        // 4. 根据条件左侧递归遍历
        if (low < l) {
            quickSort(array, low, l - 1);
        }
        // 5. 根据条件右侧递归遍历
        if (r < high) {
            quickSort(array, r + 1, high);
        }
    }

    @Override
    public int[] sort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
        return arr;
    }
}

归并排序

public class MergeSort implements Sort {
    public static void main(String[] args) {
        int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
        // SortUtil.printSort(arr, new MergeSort());
        SortUtil.printCapability(arr, new MergeSort());
    }

    /**
     * 分 + 合 方法
     */
    public void mergeSort(int[] arr, int left, int right, int[] temp) {
        if (left < right) {
            // 中间索引
            int mid = (left + right) / 2;
            // 向左递归进行分解
            mergeSort(arr, left, mid, temp);
            // 向右递归进行分解
            mergeSort(arr, mid + 1, right, temp);
            // 合并
            merge(arr, left, mid, right, temp);
        }
    }

    /**
     * 合并的方法
     *
     * @param arr   排序的原始数组
     * @param left  左边有序序列的初始索引
     * @param mid   中间索引
     * @param right 右边索引
     * @param temp  做中转的数组
     */
    private void merge(int[] arr, int left, int mid, int right, int[] temp) {
        // 初始化i,左边有序序列的初始值
        int i = left;
        // 初始化 j, 右边有序序列的初始索引
        int j = mid + 1;
        // 指向 temp 数组的当前索引
        int t = 0;
        // (一)
        // 先把左右两边(有序)的数据按照规则填充到 temp 数组
        // 直到左右两边的有序序列,有一边处理完为止
        while (i <= mid && j <= right) {
            // 继续
            // 如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            // 即将左边的当前元素,填充到 temp 数组
            // 然后 t++, i++
            if (arr[i] <= arr[j]) {
                temp[t] = arr[i];
                ++t;
                ++i;
            } else {
                // 反之,将右边有序序列的但当前元素,填充到 temp 数组
                temp[t] = arr[j];
                ++t;
                ++j;
            }
        }
        // (二)
        // 把有剩余数据的一边的数据依次全部填充到 temp
        while (i <= mid) {
            // 左边的有序序列还有剩余元素,就全部填充到temp
            temp[t] = arr[i];
            ++t;
            ++i;
        }
        while (j <= right) {
            // 右边的有序序列还有剩余元素,就全部填充到temp
            temp[t] = arr[j];
            ++t;
            ++j;
        }
        // (三)
        // 将 temp 数组的元素拷贝到 arr
        // 注意,并不是每次都拷贝所有
        int tempLeft = left;
        t = 0;
        while (tempLeft <= right) {
            arr[tempLeft] = temp[t];
            ++t;
            ++tempLeft;
        }
    }

    @Override
    public int[] sort(int[] arr) {
        int len = arr.length;
        mergeSort(arr, 0, len - 1, new int[len]);
        return arr;
    }
}

基数排序

public class RadixSort implements Sort {

    public static void main(String[] args) {
        int[] arr = {53, 3, 542, 748, 14, 214};
        // SortUtil.printSort(arr, new RadixSort());
        SortUtil.printCapability(arr, new RadixSort());
    }

    /**
     * 基数排序方法
     */
    public int[] radixSort(int[] arr) {
        // 根据前面的推导过程,得到最终的基数排序算法
        // 1. 得到数组中最大位数的数
        // 假设第一位就是最大数
        int max = arr[0];
        for (int a : arr) {
            if (a > max) {
                max = a;
            }
        }
        // 得到最大的数是几位数
        int maxLength = 1;
        while (max > 10) {
            max /= 10;
            ++maxLength;
        }
        // 定义一个二维数组,表示10个桶,每个桶就是一个一维数组
        // 说明:
        // 1. 二维数组包含 10 个一维数组
        // 2. 为了防止放入数的时候,数据溢出,则每个一维数组(桶),大小定义为 arr.length
        // 3. 基数排序是使用空间排序换时间排序的经典算法
        int[][] bucket = new int[10][arr.length];
        // 为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶每个放入的数据个数
        int[] bucketElementCounts = new int[10];
        // 这里我们使用循环将代码处理
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            // 针对每个元素的对应位进行排序处理,第一位是个位,第二位是十位,第三位是百位
            for (int k : arr) {
                // 取出每个元素对应的位数
                int digitOfElement = k / n % 10;
                // 放入对应的桶中
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = k;
                bucketElementCounts[digitOfElement]++;
            }
            // 按照这个桶的顺序,一维数组的下标依次取出数据,放入原来的数组
            int index = 0;
            for (int k = 0; k < bucketElementCounts.length; k++) {
                // 如果桶中有数据,我们才放入原数组
                if (bucketElementCounts[k] != 0) {
                    // 循环该桶即第 k 个桶,即第 k 个一维数组,放入
                    for (int j = 0; j < bucketElementCounts[k]; j++) {
                        // 取出元素放入到 arr
                        arr[index++] = bucket[k][j];
                    }
                }
                // 第 i + 1 轮处理后,需要将每个 bucketElementCounts[i] = 0
                bucketElementCounts[k] = 0;
            }
        }
        return arr;
    }


    @Override
    public int[] sort(int[] arr) {
        return radixSort(arr);
    }
}

查找算法

线性查找算法

二分查找算法

插值查找算法

posted @ 2022-06-29 15:31  Zzzy君不见  阅读(92)  评论(0)    收藏  举报