java几种常见算法思想

稀疏数组

二维数组转稀疏数组的思路

1.遍历原始的二维数组,得到有效数据个数sum

2.根据sum可以创建稀疏数组sparseArr int[sum+1] [3]

3.将二位数组的有效数据存入到稀疏数组中

稀疏数组转二维数组

1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组

2.在读取稀疏数组后几行的数据,并赋给原始的二维数组即可

package com.shaogui.sparsearray;

/**
 * 五子棋
 */
public class SparseArray {

    public static void main(String[] args) {

        //0 表示没有棋子,1 表示黑子,2 表示蓝子
        int[][] chessArr1 = new int[11][11];
        chessArr1[1][2] = 1;
        chessArr1[2][3] = 2;
        chessArr1[4][5] = 2;
        //输出原始数组
        for (int [] row: chessArr1){
            for (int data: row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        //二维数组转稀疏数组
        int sum = 0;
        //1
        for (int i = 0; i < 11; i++){
            for (int j = 0; j < 11; j++){
                if (chessArr1[i][j] != 0){
                    sum++;
                }
            }
        }
        //2
        int[][] sparseArr = new int[sum + 1][3];
        //3
        sparseArr[0][0] = 11;
        sparseArr[0][1] = 11;
        sparseArr[0][2] = sum;
        //4
        int count = 0;
        for (int i = 0; i < 11; i++){
            for (int j = 0; j < 11; j++){
                if (chessArr1[i][j] != 0){
                    count++;
                    sparseArr[count][0] = i;
                    sparseArr[count][1] = j;
                    sparseArr[count][2] = chessArr1[i][j];
                }
            }
        }
        //输出稀疏数组
        System.out.println("-----------稀疏数组--------------");
        for (int [] row: sparseArr){
            for (int data: row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
        /**
         * 稀疏数组转二维数组
         */
        //1
        int[][] chessArr2 = new  int[sparseArr[0][1]][sparseArr[0][1]];
        //2
        for (int i = 1; i < sum + 1; i++){
            chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
        }

        //恢复后的数组
        System.out.println("-----恢复后的数组-------");
        for (int [] row: chessArr2){
            for (int data: row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
     }
}

队列(Queue)

数组模拟队列(此数组只能用一次)

package com.shaogui.alogrithm.queue;

import java.util.Scanner;

public class ArrayQueueDemo {

    private int maxSize;  //最大容量
    private int front; //队头
    private int rear; //队尾
    private int[] arr; //队列

    //初始化队列
    public ArrayQueueDemo(int maxArrSize){
        this.maxSize = maxArrSize;
        this.front = -1;
        this.rear = -1;
        this.arr = new int[maxArrSize];
    }
    //判空
    public boolean isEmpty(){
        return this.front == this.rear;
    }

    //判满
    public boolean isFull(){
        return this.rear == this.maxSize - 1;
    }

    //入队
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队已满");
            return;
        }
        this.rear++;
        this.arr[this.rear] = n;
    }
    //出队
    public int getQueue(){
        if (isEmpty()){
//            System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        front++;
        return this.arr[front];
    }

    public void showQueue(){
        if (isEmpty()){
//            System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        for (int i = 0;i < this.arr.length; i++){
            System.out.printf("arr[%d]=%d\n",i ,arr[i]);
        }
    }

    //显示队头
    public int topQueue(){
        if (isEmpty()){
//            System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        return this.arr[this.front + 1];
    }
    public static void main(String[] args) {
        ArrayQueueDemo arrayQueueDemo = new ArrayQueueDemo(3);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出");
            System.out.println("a(push): 添加数据");
            System.out.println("g(pop): 取出数据");
            System.out.println("h(top): 查看队头数据");
            key = scanner.next().charAt(0);
            switch (key){
                case 's':
                    try {
                        arrayQueueDemo.showQueue();
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'a':
                    System.out.println("请输入一个数: ");
                    int value = scanner.nextInt();
                    arrayQueueDemo.addQueue(value);
                    break;
                case 'g':
                    try {
                        int res = arrayQueueDemo.getQueue();
                        System.out.println("取出的数据为:"+res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int res = arrayQueueDemo.topQueue();
                        System.out.println("队头数据为:"+res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    System.out.println("程序退出!!!!!!!");
                    break;
            }
        }
    }
}

改进

数组模拟环形队列(此数组可以多次使用 )

满:(rear + 1) % maxSize == front

空:rear == front

个数:(rear + maxSize - front) % maxSize

package com.shaogui.alogrithm.queue;

import java.util.Scanner;

public class CircleArrayQueue {
    private int maxSize;  //最大容量
    private int front; //队头
    private int rear; //队尾
    private int[] arr; //队列

    //初始化队列
    public CircleArrayQueue(int maxArrSize){
        this.maxSize = maxArrSize;
        this.front = 0;
        this.rear = 0;
        this.arr = new int[maxArrSize];
    }
    //判空
    public boolean isEmpty(){
        return front == rear;
    }

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

    //入队
    public void addQueue(int n){
        if (isFull()){
            System.out.println("队已满");
            return;
        }
        arr[rear] = n;
        rear = (rear + 1) % maxSize;
    }
    //出队
    public int getQueue(){
        if (isEmpty()){
//            System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }

    public void showQueue(){
        if (isEmpty()){
//            System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        for (int i = front;i < (front + size()); i++){
            System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
        }
    }
    public int size(){
        return (rear + maxSize - front) % maxSize;
    }

    //显示队头
    public int topQueue(){
        if (isEmpty()){
    		//System.out.println("队是空的");
            throw new RuntimeException("队是空的");
        }
        return this.arr[this.front];
    }
    public static void main(String[] args) {
        CircleArrayQueue cricleArrayQueue = new CircleArrayQueue(4);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        while (loop){
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出");
            System.out.println("a(push): 添加数据");
            System.out.println("g(pop): 取出数据");
            System.out.println("h(top): 查看队头数据");
            key = scanner.next().charAt(0);
            switch (key){
                case 's':
                    try {
                        cricleArrayQueue.showQueue();
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'a':
                    System.out.println("请输入一个数: ");
                    int value = scanner.nextInt();
                    cricleArrayQueue.addQueue(value);
                    break;
                case 'g':
                    try {
                        int res = cricleArrayQueue.getQueue();
                        System.out.println("取出的数据为:"+res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        int res = cricleArrayQueue.topQueue();
                        System.out.println("队头数据为:"+res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    System.out.println("程序退出!!!!!!!");
                    break;
            }
        }
    }
}

链表(Linked List)

单向链表

增删改查

package com.shaogui.alogrithm.linkedlist;

public class SingleLinkedList {
    public static void main(String[] args) {
        //测试
        //创建节点
        HeroNode heroNode1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星");
        HeroNode heroNode4 = new HeroNode(4, "林冲", "豹子头");
        //创建链表
        HeroSingleLinkedList heroSingleLinkedList = new HeroSingleLinkedList();
        //添加节点
        /*heroSingleLinkedList.add(heroNode1);
        heroSingleLinkedList.add(heroNode2);
        heroSingleLinkedList.add(heroNode3);
        heroSingleLinkedList.add(heroNode4);*/
        heroSingleLinkedList.addByOrder(heroNode2);
        heroSingleLinkedList.addByOrder(heroNode4);
        heroSingleLinkedList.addByOrder(heroNode1);
        heroSingleLinkedList.addByOrder(heroNode3);
        //heroSingleLinkedList.addByOrder(heroNode3);
        System.out.println("修改之前的链表");
        heroSingleLinkedList.list();
        //修改
        HeroNode heroNode5= new HeroNode(2, "小卢", "玉麒麟~~~~");
        heroSingleLinkedList.update(heroNode5);
        //显示
        System.out.println("修改之后的链表");
        heroSingleLinkedList.list();

        System.out.println("删除之后的链表");
        heroSingleLinkedList.delete(1);
        heroSingleLinkedList.delete(4);
        heroSingleLinkedList.list();
    }
}

//定义单链表来管理英雄
class HeroSingleLinkedList{
    private HeroNode head = new HeroNode(0, "", "");

    //添加无序节点
    public void add(HeroNode node){
        //遍历链表
        HeroNode temp = head;
        while (true){
            if (temp.next == null){
                break;
            }
            temp = temp.next;
        }
        temp.next = node;
    }
    //有序添加
    public void addByOrder(HeroNode heroNode){
        HeroNode temp = head;
        boolean flag = false;
        while (true){
            if (temp.next == null){
                break;
            }
            if (temp.next.no > heroNode.no){

                break;
            }else if (temp.next.no == heroNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            //不能添加
            System.out.printf("准备插入的英雄编号 %d 已经存在,不能加入\n",heroNode.no);
        }else {
            //可以添加
            heroNode.next = temp.next;
            temp.next = heroNode;
        }
    }

    //修改节点,根据节点的no修改
    public void update(HeroNode newheroNode){
        //判断为空
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }
        HeroNode temp = head.next;
        boolean flag = false;
        while (true){
            if (temp == null){
                break;// 到达末尾
            }
            if (temp.no == newheroNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //判断找到没
        if (flag){
            temp.name = newheroNode.name;
            temp.nickname = newheroNode.nickname;
        } else {
            System.out.printf("没有找到编号 %d 的节点,不能修改\n", newheroNode.no);
        }
    }
    //删除节点,以编号删除
    public void delete(int no){
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }
        HeroNode temp = head;
        boolean flag = false;
        while (true){
            if (temp == null){
                break;
            }
            if (temp.next.no == no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.next = temp.next.next;
        }else {
            System.out.printf("要删除的 %d 节点不存在\n", no);
        }
    }
    //显示链表
    public void list(){
         if (head.next == null){
             System.out.println("链表为空");
             return;
         }
         HeroNode temp = head.next;
         while (true){
             if (temp == null){
                 break;
             }
             System.out.println(temp);;
             temp = temp.next;
         }
    }
}

//定义英雄节点
class HeroNode{
    public int no;
    public String name;
    public String nickname;
    public HeroNode next;

    public HeroNode(int hNo, String hName, String hNickname){
        this.no = hNo;
        this.name = hName;
        this.nickname = hNickname;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}

大厂面试题

/**
 *
 * @param head 链表的头节点
 * @return 获取有效节点个数
 */
public static int getLength(HeroNode head){
    if (head.next == null){
        return 0;
    }
    int len = 0;
    HeroNode cur = head.next;
    while (cur != null){
        len ++;
        cur = cur.next;
    }
    return len;
}

//查找单链表中的倒数第k个节点【新浪面试题】
/**
 * 思路:
 * 接收 head和 k
 * 获取链表长度
 * 从头开始遍历到 size-k
 */
public static HeroNode findLastIndexNode(HeroNode head, int k){
    if (head.next == null){
        return null;
    }
    int size = getLength(head);
    HeroNode temp = head.next;
    if (k <= 0 || k > size){
        return null;
    }
    int count = size - k;
    while (count-- > 0){
        temp = temp.next;
    }
    return temp;
}
//单链表反转【腾讯面试题】
public static void reverseLinked(HeroNode head){
    HeroNode reverseHead = new HeroNode(0,"","");
    if (head.next == null || head.next.next == null){
        return;
    }
    HeroNode cur = head.next;
    HeroNode next = null;
    while (cur != null){
        next = cur.next;
        cur.next = reverseHead.next;//将cur的下一个节点挂在最前端
        reverseHead.next =cur;
        cur = next;
    }
    head.next = reverseHead.next;
}
//利用栈反向打印链表【百度面试题】(不会改变链表结构)
public static void reveseListPrint(HeroNode head){
    Stack<HeroNode> s = new Stack<HeroNode>(); //创建栈
    HeroNode cur = head.next;
    if (head.next == null){
        return;
    }
    while (true){
        if (cur == null){
            break;
        }
        s.push(cur); //入栈
        cur = cur.next;
    }
    int size = s.size();
    for (int i = 0; i < size ; i++){
        System.out.println(s.pop());  //出栈
    }
}
//合并两个单向链表
public  static void mergeLinkedList(HeroNode head1, HeroNode head2){
        HeroNode cur1 = null;
        HeroNode cur2 = null;
        HeroNode temp = null;
        if (head1.next == null || head2.next == null){
            return;
        }
        cur1 = head1.next;
        cur2 = head2.next;
        temp = head1;
        while (true){
            if (cur1 == null){
                temp.next = cur2;
                break;
            }
            if (cur2 == null){
                temp.next = cur1;
                break;
            }
            if (cur1.no >= cur2.no){
                temp.next = cur2;
                cur2 = cur2.next;
            }else {
                temp.next = cur1;
                cur1 = cur1.next;
            }
            temp = temp.next;
        }
}

双向链表

package com.shaogui.alogrithm.linkedlist;

public class DoubleLinkedListDemo {

    public static void main(String[] args) {
        HeroNode2 heroNode1 = new HeroNode2(1, "宋江", "及时雨");
        HeroNode2 heroNode2 = new HeroNode2(3, "卢俊义", "玉麒麟");
        HeroNode2 heroNode3 = new HeroNode2(2, "吴用", "智多星");
        HeroNode2 heroNode4 = new HeroNode2(4, "林冲", "豹子头");
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.add(heroNode2);
        doubleLinkedList.add(heroNode4);
        doubleLinkedList.add(heroNode1);
        doubleLinkedList.add(heroNode3);
        //排序后的双向链表
        doubleLinkedList.list();
    }

}
class DoubleLinkedList{
    private HeroNode2 head = new HeroNode2(0, "", "");

    public HeroNode2 getHead() {
        return head;
    }
    //添加无序节点
    public void add(HeroNode2 node){
        //遍历链表
        HeroNode2 temp = head;
        while (true){
            if (temp.next == null){
                break;
            }
            temp = temp.next;

        }
        //形成双向
        temp.next = node;
        node.pre = temp;
    }
    //修改节点,根据节点的no修改
    public void update(HeroNode2 newheroNode){
        //判断为空
        if (head.next == null){
            System.out.println("链表为空~");
            return;
        }
        HeroNode2 temp = head.next;
        boolean flag = false;
        while (true){
            if (temp == null){
                break;// 到达末尾
            }
            if (temp.no == newheroNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        //判断找到没
        if (flag){
            temp.name = newheroNode.name;
            temp.nickname = newheroNode.nickname;
        } else {
            System.out.printf("没有找到编号 %d 的节点,不能修改\n", newheroNode.no);
        }
    }
    //删除节点,以编号删除
    public void delete(int no){
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }
        HeroNode2 temp = head.next;
        boolean flag = false;
        while (true){
            if (temp == null){
                break;
            }
            if (temp.no == no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.pre.next = temp.next;
            if (temp.next != null){
                temp.next.pre = temp.pre;
            }
        }else {
            System.out.printf("要删除的 %d 节点不存在\n", no);
        }
    }
    //遍历双向链表
    //显示链表
    public void list(){
        if (head.next == null){
            System.out.println("链表为空");
            return;
        }
        HeroNode2 temp = head.next;
        while (true){
            if (temp == null){
                break;
            }
            System.out.println(temp);;
            temp = temp.next;
        }
    }
}


class HeroNode2{
    public int no;
    public String name;
    public String nickname;
    public HeroNode2 next;
    public HeroNode2 pre;

    public HeroNode2(int hNo, String hName, String hNickname){
        this.no = hNo;
        this.name = hName;
        this.nickname = hNickname;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}

单向环形列表

例:约瑟夫环

Josephu问题为:设编号为1, 2, …n的n个人围坐一圈,约定编号为k (1<=k<=n) 的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生个出队编号 的序列。

思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUj3NFfL-1649853798814)(images/dd.png)]

package com.shaogui.alogrithm.linkedlist;

public class Josephu {

    public static void main(String[] args) {
        CircleSingleLisnkedList circleSingleLisnkedList = new CircleSingleLisnkedList();
        circleSingleLisnkedList.addBoy(20);
        circleSingleLisnkedList.showBoy();
        circleSingleLisnkedList.Josephu(1,2,20);
    }
}

//创建环形列表

/**
 * 1.先创建第一个节点,让first指回该节点,开形成环形
 * 2.后面当我们每创建- -个新的节点,就把该节点,加入到已有的环形链表中即可.
 */
class CircleSingleLisnkedList{
    private Boy first = null;
    public void addBoy(int nums){
        if (nums < 1){
            System.out.println("nums不正确");
            return;
        }
        Boy cur = null;
        //使用for创建环形列表
        for (int i = 1; i <=nums; i++){
            //根据编号创建小孩
            Boy boy = new Boy(i);
            if (i == 1){
                first = boy;
                first.setNext(first);
                cur = first;
            }
            else{
                cur.setNext(boy);
                boy.setNext(first);
                cur = boy;
            }
        }
    }

    public void showBoy(){
        if (first == null){
            System.out.println("链表为空");
            return;
        }
        Boy cur = first;

        while (true){
            System.out.printf("小孩的标号%d\n",cur.getNo());
            if (cur.getNext() == first){
                break;
            }
            cur = cur.getNext();
        }
    }
    //Josephu

    /**
     *
     * @param startNo 从第几个小孩开始
     * @param countNum 数几下
     * @param nums 最初有几个小孩
     */
    public void Josephu(int startNo, int countNum, int nums){
        if (first == null || startNo < 1 || startNo > nums){
            System.out.println("参数输入有误,请重新输入");
            return;
        }
        Boy helper = first;
        while (true){
            if (helper.getNext() == first){
                break;
            }
            helper = helper.getNext();
        }
        //小孩报数前,先让first和helper 移动k - 1次
        for (int i = 0; i < startNo - 1; i++){
            first = first.getNext();
            helper = helper.getNext();
        }
        //当小孩报数时,让first和helper指针同时的移动m - 1次,然后出圈
        //这里是一个循环操作,知道圈中只有一一个节点
        while (true){
            if (helper == first){
                break;
            }
            for (int i = 0; i < countNum -1; i++){
                first = first.getNext();
                helper = helper.getNext();
            }
            //first 指向的节点是出圈的小孩
            System.out.printf("%d --->",first.getNo());
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("%d",first.getNo());
    }
}

//初始化
class Boy{
    private int no;
    private Boy next;//指向下一个节点

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

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public Boy getNext() {
        return next;
    }

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

栈(Stack)

先进后出

数组模拟栈

实现栈的思路分析
1.使用数组来模拟栈
2.定义一个top来表示栈顶,初始化为-1
3.入栈的操作,当有数据加入到栈时,top++; stack[top]= data;
4.出栈的操作,int value = stack[top];top–;return value

package com.shaogui.alogrithm.stack;

import java.util.Scanner;

public class ArrayStackDemo {
    //创建栈
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(4);
        String key = "";
        boolean loop = true; //是否退出菜单
        Scanner scanner = new Scanner(System.in);
        while (loop){
            System.out.println("show:表示显示栈");
            System.out.println("exit:退出程序");
            System.out.println("push:表示添加数据到栈(入栈)");
            System.out.println("pop:表示从栈中取出数据(出栈)");
            System.out.println("请输入:");
            key = scanner.next();
            switch (key){
                case "show":
                    arrayStack.list();
                    break;
                case "push":
                    System.out.println("请输入要入栈的数:");
                    int value = scanner.nextInt();
                    arrayStack.push(value);
                    break;
                case "pop":
                    try {
                        int pop = arrayStack.pop();
                        System.out.printf("出栈的数据是:%d\n", pop);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    break;
                default:
                    System.out.println("您输入的文字不在功能列表里面,请重新输入");
                    break;

            }
        }
        System.out.println("程序退出");
    }
}

//实现栈
class ArrayStack{

    private int maxSize;  //栈大小
    private int[] stack;  //数组模拟栈
    private int top = -1;  //栈顶

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

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

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

    //入栈
    public void push(int value){
        if (isFull()){
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }
    //出栈
    public int pop(){
        if (isEmpty()){
            throw  new RuntimeException("栈空");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //遍历栈
    public void list(){
        if (isEmpty()){
            System.out.println("栈空");
            return;
        }
        for (int i = top; i >= 0; i--){
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }
}

链表模拟栈

栈实现综合计算器

使用栈完成表达式的计算 思路
1.通过一个index值(索引),来遍历我们的表达式
2.如果我们发现是一个数字,就直接入数栈
3.如果发现扫描到是一个符号,就分如下情况
3.1如果发现当前的符号栈为空,就直接入栈
3.2如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中
的操作符,就需要从数栈中pop出两个数在从符号栈中pop出一个符号,进行运算,
将得到结果,入数栈,然后将当前的操作符入符号栈,如果当前的操作符的优先级 大于栈中的操作符,就直接入符号栈。
4.当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行。
5.最后在数栈只有一个数字,就是表达式的值

package com.shaogui.alogrithm.stack;

public class Calculator {
    public static void main(String[] args) {
        String expression = "30+2*6-2";
        NumSatck numSatck = new NumSatck(10);
        NumSatck operSatck = new NumSatck(10);
        //定义需要的相关变量
        int index = 0;
        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch = ' '; // 每次扫描的char
        String keepNum = ""; //用于拼接
        while (true){
            ch = expression.substring(index, index + 1).charAt(0);
            if (operSatck.isOper(ch)){
                //判断当前符号栈是否为空
                if (!operSatck.isEmpty()){
                    if (operSatck.priority(ch) <= operSatck.priority(operSatck.top())){
                        num1 = numSatck.pop();
                        num2 = numSatck.pop();
                        oper = operSatck.pop();
                        res = numSatck.cal(num1, num2, oper);
                        numSatck.push(res);
                        operSatck.push(ch);
                    } else {
                        operSatck.push(ch);
                    }
                }else {
                    operSatck.push(ch);
                }
            }else {
                //处理多位数
                //numSatck.push((ch - 48));
                keepNum += ch;
                if (index == expression.length() - 1){
                    numSatck.push(Integer.parseInt(keepNum));
                }
                else {
                    if (operSatck.isOper(expression.substring(index + 1, index + 2).charAt(0))){
                        numSatck.push(Integer.parseInt(keepNum));
                        keepNum = "";
                    }
                }

            }
            //让index+1
            index++;
            if (index >= expression.length()){
                break;
            }
        }
        while (true){
            if (operSatck.isEmpty()){
                break;
            }
            num1 = numSatck.pop();
            num2 = numSatck.pop();
            oper = operSatck.pop();
            res = numSatck.cal(num1, num2, oper);
            numSatck.push(res);

        }
        System.out.printf("表达式 %s=%d\n", expression, numSatck.pop());
    }
}


// 创建一个栈
class NumSatck{

    private int maxSize;  //栈大小
    private int[] stack;  //数组模拟栈
    private int top = -1;  //栈顶

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

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

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

    //入栈
    public void push(int value){
        if (isFull()){
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }
    //出栈
    public int pop(){
        if (isEmpty()){
            throw  new RuntimeException("栈空");
        }
        int value = stack[top];
        top--;
        return value;
    }
    //栈顶元素
    public int top(){
        if (isEmpty()){
            throw  new RuntimeException("栈空");
        }
        return stack[top];
    }
    //遍历栈
    public void list(){
        if (isEmpty()){
            System.out.println("栈空");
            return;
        }
        for (int i = top; i >= 0; i--){
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }
    //返回运算符的优先级
    public int priority(int oper){
        if (oper == '*' || oper == '/'){
            return 1;
        }else if (oper == '+' || oper =='-'){
            return 0;
        }else {
            return -1;
        }
    }
    //判断是不是运算符
    public boolean isOper(char val){
        return val == '+' || val == '-' || val == '*' || val == '/';
    }
    //计算
    public int cal(int num1, int num2, int oper){
        int res = 0;
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res;
    }
}

逆波兰式计算

package com.shaogui.alogrithm.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
    public static void main(String[] args) {
        // (3+4)x5-6 => 3 4 + 5 x 6 -
        String suffixExperssion = "3 4 + 5 x 6 -";

        List<String> rpnList = getList(suffixExperssion);
        int res = calculate(rpnList);
        System.out.printf("表达式%s = %d", suffixExperssion, res);
    }
    public static List<String> getList(String suffixExperssion){
        //将suffixExperssion分割
        String[] split = suffixExperssion.split(" ");
        List<String> list = new ArrayList<String>();
        for (String ele: split){
            list.add(ele);
        }
        return list;
    }
    public static int calculate(List<String> ls){
        Stack<String> stack = new Stack<>();
        for (String item: ls){
            if (item.matches("\\d+")){
                //入栈
                stack.push(item);
            }else {
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int res = 0;
                if (item.equals("+")){
                    res = num1 + num2;
                }else if (item.equals("-")){
                    res = num2 - num1;
                }else if (item.equals("x")){
                    res = num1 * num2;
                }else if (item.equals("/")){
                    res = num2 / num1;
                }else {
                    throw new RuntimeException("运算符有误");
                }
                stack.push(res + "");
            }
        }
        return Integer.parseInt(stack.pop());
    }
}

中缀表达式转后缀表达式

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gdhLZJKm-1649853798815)(images/dddddd.png)]

package com.shaogui.alogrithm.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
    public static void main(String[] args) {
        // (3+4)x5-6 => 3 4 + 5 x 6 -
//        String suffixExperssion = "3 4 + 5 x 6 -";
//
//        List<String> rpnList = getList(suffixExperssion);
//        int res = calculate(rpnList);
//        System.out.printf("表达式%s = %d", suffixExperssion, res);
        String expression = "1+((2+3)*4)-5";
        List<String> infixExpressionList = toInfixExpressionList(expression);
        System.out.println("中缀:"+infixExpressionList);
        List<String> parseSuffixExpressionList = parseSuffixExpressionList(infixExpressionList);
        System.out.println(parseSuffixExpressionList);
    }
    public static List<String> getList(String suffixExperssion){
        //将suffixExperssion分割
        String[] split = suffixExperssion.split(" ");
        List<String> list = new ArrayList<String>();
        for (String ele: split){
            list.add(ele);
        }
        return list;
    }
    public static int calculate(List<String> ls){
        Stack<String> stack = new Stack<>();
        for (String item: ls){
            if (item.matches("\\d+")){
                //入栈
                stack.push(item);
            }else {
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int res = 0;
                if (item.equals("+")){
                    res = num1 + num2;
                }else if (item.equals("-")){
                    res = num2 - num1;
                }else if (item.equals("*")){
                    res = num1 * num2;
                }else if (item.equals("/")){
                    res = num2 / num1;
                }else {
                    throw new RuntimeException("运算符有误");
                }
                stack.push(res + "");
            }
        }
        return Integer.parseInt(stack.pop());
    }
    public static List<String> toInfixExpressionList(String s){
        List<String> list = new ArrayList<>();
        int i = 0;
        String str = "";//多位数拼接
        char ch = ' ';
        do {
            if ((ch = s.charAt(i)) < 48 || (ch = s.charAt(i)) > 57){
                list.add("" + ch);
                i++;
            }else {
                str = "";
                while (i < s.length() && (ch = s.charAt(i)) >= 48 && (ch = s.charAt(i)) <= 57){
                    str += ch;
                    i++;
                }
                list.add(str);
            }
        }while (i < s.length());
        return list;
    }
    public static List<String> parseSuffixExpressionList(List<String> list){
        //定义栈
        Stack<String> s1 = new Stack<String>(); //符号栈
        List<String> s2 = new ArrayList<String>();

        //遍历list
        for (String item: list){
            //如果是一个数,则入s2
            if (item.matches("\\d+")){
                s2.add(item);
            } else if (item.equals("(")){
                s1.push(item);
            } else if (item.equals(")")){
                //如果是右括号则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一 对括号丢弃
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                //需将 ( 删除
                s1.pop();
            } else {
                //当item的优先级小于等于s1栈项运算符,将s1栈项 的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //还需将 item 入s2
                s1.push(item);
            }
        }

        //将s1中剩余的运算符依次弹出并加入s2
        while (s1.size() != 0){
            s2.add(s1.pop());
        }
        return s2;
    }
}
//返回优先级高低
class Operation{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;

    public static int getValue(String operation){
        int res = 0;
        switch (operation){
            case "+":
                res = ADD;
                break;
            case "-":
                res = SUB;
                break;
            case "*":
                res = MUL;
                break;
            case "/":
                res = DIV;
                break;
            default:
                System.out.println("不存在该运算符");
                break;
        }
        return res;
    }
}

递归

递归需要遵守的重要规则

1)执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
2)方法的局部变量是独立的,不会相互影响,比如n变量
3) 如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据.
4)递归必须向退出递归的条件逼近,否则就是无限递归
5) 当一个方法执行完毕,或者遇到return, 就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。

迷宫路径

package com.shaogui.alogrithm.recursion;

public class MiGong {


    public static void main(String[] args) {
        //创建一个二维数组,模拟迷宫
        int[][] map = new int[8][7];
        //使用 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;
        }
        //设置挡板
        map[3][1] = 1;
        map[3][2] = 1;
        //输出地图
        setWay(map,1, 1);
        for (int i = 0; i < 8; i++){
            for (int j = 0; j < 7; j++){
                System.out.print(map[i][j]+" ");
            }
            System.out.println();
        }

    }

    /**
     *
     * 终点默认右下角 map[6][5]
     * 2 表示走的路径 3 表示走过但走不通
     * 下-》右-》上-》左
     * @param map 地图
     * @param i 从哪一行开始
     * @param j 从哪一列开始
     * @return 找到没
     */
    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)){ //向下走
                    return true;
                } else if (setWay(map, i, j + 1)){ //向右走
                    return true;
                } else if (setWay(map, i - 1, j)){ //向上
                    return true;
                } else if (setWay(map, i, j - 1)){  //向左走
                    return true;
                }else {
                    //说明该点走不通
                    map[i][j] = 3;
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}

八皇后问题

八皇后问题算法思路分析

  1. 第一个皇后先放第一行第一列
  2. 第二个皇后放在第二行第一列、然后判断是否0K, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
  3. 继续第三个皇后,还是第一-列、第二列…直到第8个皇后也能放在一一个不冲突的位置,算是找到了一个正确解
  4. 当得到一-个正确解时,在栈回退到上一一个栈时,就会开始回溯,即将第
    一个皇后,放到第一列的所有正确解,全部得到。
  5. 然后回头继续第一个皇后放第二列,后面继续循环执行1,2,3,4的步骤

说明:理论上应该创建一个二维数组来表示棋盘,但是实际上可以通过算法,用一个一维数组即可解决问题。arr[8]= {0,4,7,5,2, 6, 1, 3} //对应arr下标表示第几行,即第几个皇后,arr[i] =val, val表示第i+1个皇后,放在第i+1行的第val+1列

package com.shaogui.alogrithm.recursion;

public class Queue8 {

    //定义一个max表示有多少个皇后
    int max = 8;
    //定义数组,保存皇后放置的位置
    int[] arr = new int[max];
    static int count = 0;
    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.println("一共有:" + count +"次解法");
    }
    //放置皇后
    public void check(int n){
        if (n == max){
            print();
            return;
        }
        //依次放入放入皇后
        for (int i = 0; i < max; i++) {
            //先把当前这个皇后 n ,放在 该行第 1 列
            arr[n] = i;
            //判断这个皇后放在第 i 列 是否有冲突
            if (jude(n)){  //不冲突
                //接着放置 n+1 个皇后
                check(n + 1);
            }
            //如果冲突,放在下一列
        }
    }
    //判断当前位置可不可以放置这个位置
    /**
     *
     * @param n  放置的第几个皇后
     * @return
     */
    public boolean jude(int n){
        for (int i = 0; i < n; i++) {
            // arr[i] == arr[n] 表示 第n个皇后是否和前面的n-1个皇后在同一列
            //Math.abs(n - i) == Math.abs(arr[n] - arr[i]) 表示 第n个皇后是否和第i个皇后是否在同一斜线上
            if (arr[i] == arr[n] || (Math.abs(n - i) == Math.abs(arr[n] - arr[i]))){
                return false;
            }
        }
        return true;
    }
    //将皇后摆放的位置输出
    public void print(){
        count++;
        for (int i = 0; i < max; i++){
            System.out.printf(arr[i] + " ");
        }
        System.out.println();
    }

}

排序

思想:

插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素, 把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

插入排序

package com.shaogui.alogrithm.sort;

import java.util.Arrays;

public class InsertSort {


    public static void main(String[] args) {
        int[] arr = {101, 34, 119, 1};
        insertSort(arr);
    }

    //插入排序
    public static void insertSort(int[] arr){
        // 定义一个待插入的数
        int insertVal = 0;
        int insertIndex = 0;
        for (int i = 1; i < arr.length ; i++) {
            insertVal = arr[i];
            insertIndex = i - 1;

            //给insertVal找位置
            while (insertIndex >= 0 && insertVal < arr[insertIndex]){
                //移动
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            if (insertIndex + 1 != i){
                arr[insertIndex + 1] = insertVal;
            }

        }

        System.out.println(Arrays.toString(arr));
    }
}

直接插入排序

希尔排序

基本思想:是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法终止

package com.shaogui.alogrithm.sort;

import java.util.Arrays;

public class ShellSort {

    public static void main(String[] args) {
        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        System.out.println(Arrays.toString(arr));
        shellSort2(arr);
        System.out.println(Arrays.toString(arr));

    }

    //使用逐步推到的方式编写希尔排序
    //希尔排序时,对有序序列在插入时采用交换法
    public static void shellSort(int[] arr){
        //希尔排序第一轮
        //因为第一轮排序,是将10个数据分成了5组
        /*for (int i = 5; i < arr.length; i++) {
            //遍历各组中所有元素(共5组,每组两个元素),步长为5
            for (int j = i - 5; j >= 0; j-=5) {
                //交换--从小到大 当前元素大于加上步长的那个元素,则交换
                if (arr[j] > arr[j + 5]){
                    int temp = arr[j];
                    arr[j] = arr[j + 5];
                    arr[j + 5] = temp;
                }
            }
        }*/
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                //遍历各组中所有元素(共5组,每组两个元素),步长为5
                for (int j = i - gap; j >= 0; j-=gap) {
                    //交换--从小到大 当前元素大于加上步长的那个元素,则交换
                    if (arr[j] > arr[j + gap]){
                        int temp = arr[j];
                        arr[j] = arr[j + gap];
                        arr[j + gap] = temp;
                    }
                }
            }
        }
    }

    //对交换式的希尔排序进行优化->移位法
    public static void shellSort2(int[] arr){
        //增量gap,并逐步缩小增量
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) {
            //从第gap个元素,逐个对其所在的组进行直接插入排序
            for (int i = gap; i < arr.length; i++) {
                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;
                    }
                    //找到位置
                    arr[j] = temp;
                }
            }
        }
    }
}

选择排序

思想:

选择排序(select sorting) 也是一种简单的排序方法。它的基本思想是:第
一次从arr[0]~arr[n-1]中选取最小值,与arr[0]交换, 第二次从arr[1]~arr [n-1]中选取最小值,与arr[1]交换, 第三次从arr[2]~ arr[n-1]中选取最小值,与arr[2]交换,…第i次从arr[i-1]~arr[n-1]中选取最小值,与arr[i-1]交换,…第n-1次从arr[n-2]^ arr[n-1]中选取最小值,与arr [n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列。

简单选择排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rJYx1xMC-1649853798816)(images/Snipaste_2020-07-27_09-31-27.png)]

package com.shaogui.alogrithm.sort;

import java.util.Arrays;

public class SelectSort {
    public static void main(String[] args) {
        int[] arr={101, 34, 119, 1};
        selectSort(arr);
    }

    //选择排序
    public static void selectSort(int[] arr){


        /*for (int i = 1; i < arr.length; i++){
            if (arr[i] < min){
                min = arr[i];
                minIndex = i;
            }
        }*/
        //将最小值与arr[0]交换
        /*arr[minIndex] = arr[0];
        arr[0] = min;
        System.out.println("第一轮:");
        System.out.println(Arrays.toString(arr));*/

        for (int i = 0; i < arr.length - 1; i++){
            //放置最小的那个数
            int minIndex = i;
            int min = arr[i];
            for (int j = i + 1; j < arr.length; j++) { //找到 n-1个中的最小的一个
                if (arr[j] < min){ 
                    min = arr[j];
                    minIndex = j;
                }
            }
            if (minIndex != i){ //找到后与前面的进行交换
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
//            System.out.println("第"+(i+1)+"轮:");
//            System.out.println(Arrays.toString(arr));
        }
        System.out.println(Arrays.toString(arr));
    }
}

堆排序

交换排序

冒泡排序

package com.shaogui.alogrithm.sort;

import java.util.Arrays;

public class BubbleSort {

    public static void main(String[] args) {
        int[] arr={3, 9, -1, 10, 20};

        int temp = 0; //中间变量,交换
        boolean flag = false; //优化
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++){ //将第几大的数交换到相应位置
                if (arr[j] > arr[j + 1]){
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            System.out.println("第" + (i+1) + "趟排序后的数组");
            System.out.println(Arrays.toString(arr));
            if (!flag){  //表示一次交换都没有发生,则表示此时数组已经排好序
                break;
            }
            else {
                flag = false;
            }
        }
        System.out.println("排序成功的数组:");
        System.out.println(Arrays.toString(arr));
    }
}

快速排序

归并排序

基数排序(桶排序)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值