数据结构与算法

132 阅读15分钟

稀疏数组

概念

  • 当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。

  • 稀疏数组的处理方式是:记录数组一共有几行几列,有多少个不同值;把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模

  • 如下图:左边是原始数组,右边是稀疏数组

    image-20220803134824493转存失败,建议直接上传图片文件

代码实现

package sparse;

/**
 * @author zwf
 * @Package: sparse
 * @ClassName: SparseArray
 * @Description:
 * @date 2022/8/3 13:02
 */
public class SparseArray {
    public static void main(String[] args) {
        //创建一个原始的二维数组11*11
        int chessArr1[][]=new int[11][11];
        chessArr1[1][2]=1;
        chessArr1[2][3]=2;
        chessArr1[2][4]=4;
        //输出原始的二维数组
        System.out.println("===================原始二维数组==============================");
        for (int[] row:chessArr1){
            for (int data:row){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
        //转稀疏数组
        //  1.获取非零值的个数
        int sum=0;//累加器用于记录非零值的个数
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[i].length; j++) {
                if(chessArr1[i][j]!=0){
                    sum++;
                }
            }
        }
        //  2.初始化二维稀疏数组
        int[][] sArray = new int[sum + 1][3];
        //  3.给第一行赋值
        sArray[0][0]=sArray[0][1]=11;
        sArray[0][2]=sum;
        //  4.给元素赋值
        int count=0;
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j = 0; j < chessArr1[i].length; j++) {
                if(chessArr1[i][j]!=0){
                    count++;
                    sArray[count][0]=i;
                    sArray[count][1]=j;
                    sArray[count][2]=chessArr1[i][j];
                }
            }
        }
        //输出稀疏数组
        System.out.println("==================稀疏数组:==========================");
        for (int[] arr:sArray){
            System.out.printf("%d\t%d\t%d\t\n",arr[0],arr[1],arr[2]);
        }
        System.out.println("========================转原始数组========================");
        //初始化原始数组
        int[][] arr = new int[sArray[0][0]][sArray[0][1]];
        //遍历稀疏数组
        for (int i = 1; i < sArray.length; i++) {
            arr[sArray[i][0]][sArray[i][1]]=sArray[i][2];
        }
        for (int[] ints : arr) {
            for (int date:ints){
                System.out.printf("%d\t",date);
            }
            System.out.println();
        }

    }


}

效果如图:

image-20220803134824495转存失败,建议直接上传图片文件

队列

数组模拟队列

单向队列

package queue;

/**
 * @author zwf
 * @Package: queue
 * @ClassName: ArrayQueueDemo
 * @Description: 数组模拟队列 队列(先进先出)
 * @date 2022/8/4 20:14
 */
public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        arrayQueue.addQueue(1);
        arrayQueue.addQueue(2);
        arrayQueue.addQueue(3);
        System.out.println(arrayQueue.getQueue());
        arrayQueue.showQueue();
    }
}
//使用数组模拟队列-编写一个ArrayQueue类
class ArrayQueue{
    private int maxSize;//表示数组的最大容量
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//该数据用于存放数据,模拟队列
    //创建队列的构造器
    public ArrayQueue(int maxSize){
        this.maxSize=maxSize;
        arr=new int[maxSize];
        front=-1; //指向队列头部,分析出front是指向队列头的前一个位置。
        rear=-1;// 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
    }
    //创建队列的构造器
    public ArrayQueue(){
        this.maxSize=5;//默认空间
        arr=new int[maxSize];
        front=-1; //指向队列头部,分析出front是指向队列头的前一个位置。
        rear=-1;// 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
    }
    //判断队列是否满
    public boolean isFull(){
        return rear==maxSize-1;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return rear==front;
    }
    //入队
    public void addQueue(int n){
        //判断队列容量是否满
        if (isFull()){
            System.out.println("队列已满,不能加入数据");
            return;
        }
        arr[++rear]=n;
    }

    //出队列操作getQueue
    public int getQueue(){
        //判断队列是否为空
        if (isEmpty()){
            throw new RuntimeException("该队列为空不能取数据");
        }
        return arr[++front];
    }
    //显示队列数据
    public void showQueue(){
        //遍历
        if (isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }
        for (int i=0;i<arr.length;i++){
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }
}

环形队列

package queue;

import java.util.Map;
import java.util.Scanner;

/**
 * @author zwf
 * @Package: queue
 * @ClassName: CircleArrayQueueDemo
 * @Description: 数值实现环形队列
 * @date 2022/8/9 16:38
 */
public class CircleArrayQueueDemo {
    public static void main(String[] args) {
        //测试一把
        System.out.println("测试数组模拟环形队列的案例~~~");

        // 创建一个环形队列
        CircleQueue queue = new CircleQueue(4); //说明设置4, 其队列的有效数据最大是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(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 查看队列头的数据");
            key = scanner.next().charAt(0);// 接收一个字符
            switch (key) {
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输出一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g': // 取出数据
                    try {
                        int res = queue.getQueue();
                        System.out.printf("取出的数据是%d\n", res);
                    } catch (Exception e) {
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h': // 查看队列头的数据
                    try {
                        int res = queue.headQueue();
                        System.out.printf("队列头的数据是%d\n", res);
                    } catch (Exception e) {
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e': // 退出
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出~~");
    }
}
class CircleQueue{
    private int MaxSize;//设置队列的容量
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//该数据用于存放数据,模拟队列
    //创建构造器
    public CircleQueue(int Size){
        this.front=0;
        this.rear=0;
        this.MaxSize=Size;
        arr=new int[MaxSize];
    }
    //判断队列是否满
    public boolean isFull(){
        return (rear+1)%MaxSize==front;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return rear==front;
    }
    //入队
    public void addQueue(int n){
        //判断队列容量是否满
        if (isFull()){
            System.out.println("队列已满,不能加入数据");
            return;
        }
        arr[rear]=n;
        rear=(rear+1)%MaxSize;
    }
    //出队列操作getQueue
    public int getQueue(){
        //判断队列是否为空
        if (isEmpty()){
            throw new RuntimeException("该队列为空不能取数据");
        }
        int value=arr[front];
        front=(front+1)%MaxSize;
        return value;
    }
    //显示队列数据
    public void showQueue(){
        //遍历
        if (isEmpty()){
            System.out.println("队列空的,没有数据");
            return;
        }
        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 headQueue() {
        if (isFull()){
            return arr[front%MaxSize];
        }
        return -1;
    }
}

链表

单向链表

package linkedlist;

import java.util.Stack;

/**
 * @author zwf
 * @Package: linkedlist
 * @ClassName: SingleLinked01
 * @Description:
 * @date 2022/8/20 18:55
 */
public class SingleLinked01 {
    public static void main(String[] args) {
//        创建节点
        Hero hero1 = new Hero(1, "松江", "及时雨");
        Hero hero2 = new Hero(2, "卢骏义", "玉麒麟");
        Hero hero3 = new Hero(3, "吴用", "智多星");
        Hero hero4 = new Hero(4, "林冲", "豹子头");
        //创建链表
        HeroLinkedList linkedList = new HeroLinkedList();
        linkedList.addByOrder(hero3);
        linkedList.addByOrder(hero4);
        linkedList.addByOrder(hero1);
        linkedList.addByOrder(hero2);
        //修改
        linkedList.update( new Hero(4, "林冲", "zwf"));
        System.out.println("根据编号打印"+linkedList.findLastIndexNode(4));
        //删除
        linkedList.del(4);
        linkedList.list();
        System.out.println("逆序输出:");
        linkedList.reversePrint();
        System.out.println("反转");
        linkedList.reversetList();
        linkedList.list();
        System.out.println("输出节点个数"+linkedList.size());
    }

}
class HeroLinkedList{
    private Hero head=new Hero(0,"","");//头节点

    /**
     * 添加
     * @param hero
     */
    public void add(Hero hero){
        Hero temp=head;
        while (temp.next!=null){
            temp=temp.next;
        }
        temp.next=hero;
    }
    /**
     * 按编号顺序添加
     * @param hero
     */
    public void addByOrder(Hero hero){
        Hero temp=head;
        boolean flag=false;//记录当前编号是否存在
        while (true){
            if (temp.next==null){
                break;
            }
            if (temp.next.no>hero.no){
                break;
            }else if (temp.next.no== hero.no){
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){
            System.out.printf("准备插入的英雄的编号%d已经存在了,不能加入\n",hero.no);
        }else {
            hero.next=temp.next;
            temp.next=hero;
        }
    }
    /**
     * 删除
     * @param no
     */
    public void  del(int no){
        Hero temp=head;
        boolean flag=false;
        while (true){
            if (temp.next==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);
        }
    }
    /**
     * 修改
     * @param hero
     */
    public void update(Hero hero){
        //判断是否为空
        if (head.next==null){
            System.out.println("链表为空~~");
            return;
        }
         //找到需要修改的节点,根据no编号
        Hero temp=head.next;
        boolean flag=false;
        while (true){
            if (temp==null){
                break;
            }
            if (temp.no== hero.no){
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){
            temp.name= hero.name;
            temp.niceName= hero.niceName;
        }else {
            System.out.printf("没有找到编号%d的节点,不能修改\n",hero.no);
        }
    }
    /**
     * 遍历
     */
    public void list(){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("当前链表为空");
            return;
        }
        Hero temp=head.next;
        while (true){
            //判断是否到链表最后
            if (temp==null){
                break;
            }
            //输出节点信息
            System.out.println(temp);
            temp=temp.next;
        }

    }
    /**
     * 获取单链表中有效节点个数
     */
    public int size(){
        if (head.next==null){
            return 0;
        }
        int len=0;
        Hero temp=head.next;
        while (temp!=null){
            len++;
            temp=temp.next;
        }
        return len;
    }
    /**查找单链表中的倒数第k个节点
     * 1.编写一个方法,接收head节点,同时接收一个index
     * 2.index表示倒数第index个节点
     * 3.先把链表从头到尾遍历,得到链表的总的长度getLength
     * 4.得到size后,我们从链表的第一个开始遍历(size-index)个就可以得到
     * 5.如果找到了,则返回该节点,否则返回null
     */
    public  Hero findLastIndexNode(int index){
        if (head.next==null){
            return null;
        }
        //第一个遍历得到链表的长度(节点个数)
        int size = size();
        if (index<=0||index>size){
            return null;
        }
        Hero cur=head.next;
        for (int i=0;i<size-index;i++){
            cur=cur.next;
        }
        return cur;
    }
    /**
     *单向链表反转
     * 1.先定义一个节点reverseHead=new HeroNode();
     * 2.从头到尾遍历原来的链表,每一个节点,就将其取出,并放到新链表reversHead的最前端
     * 3.原来的链表的head.next=reverseHead.next
     */
    public void reversetList() {
        if (head.next==null||head.next.next==null){
            return;
        }
        Hero next=null;
        Hero cur=head.next;
        Hero reverseHead=new Hero(0,"","");
        while (cur!=null){
            next=cur.next;
            cur.next=reverseHead.next;
            reverseHead.next=cur;
            cur=next;
        }
        head.next=reverseHead.next;
    }
    /**
     * 逆序打印
     * 1.利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,实现逆序打印的效果
     */
    public void reversePrint(){
        if(head.next==null){
            return;
        }
        //创建一个栈,将各个节点压入栈
        Stack<Hero> stack = new Stack<>();
        Hero cur=head.next;
        //将链表的所有节点压入栈
        while (cur!=null){
            stack.push(cur);
            cur=cur.next;
        }
        //将栈中的节点进行打印,出栈
        while (stack.size()>0){
            System.out.println(stack.pop());
        }
    }
}
class Hero{
    public int no;
    public String name;
    public String niceName;
    public Hero next;
    public Hero(int no,String name,String niceName){
        this.no=no;
        this.name=name;
        this.niceName=niceName;
    }

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

环形链表(约瑟夫问题)


package linkedlist;

/**
 * @author zwf
 * @Package: linkedlist
 * @ClassName: SingleLinked02
 * @Description:
 * @date 2022/8/22 20:01
 */

/**
 * 单向环形链表
 */
public class SingleLinked02 {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5);
        circleSingleLinkedList.list();
        circleSingleLinkedList.countBoy(1,2,5);
    }
}
//创建一个环形的单向链表
class CircleSingleLinkedList{
    //创建一个first节点,当前没有编号
    private Boy first=null;
    //添加小孩节点,构建一个环形链表
    public void addBoy(int nums){
        //nums做一个数据校验
        if (nums<1){
            System.out.println("nums的值不正确");
            return;
        }
        //使用for来创建我们的环形链表
        Boy curBoy=null;//辅助指针
        for (int i=1;i<=nums;i++){
            //根据编号,创建小孩节点
            Boy boy=new Boy(i);
            //如果是第一个小孩
            if (i==1) {
                first = boy;
                first.setNext(first);
                curBoy = first;//让curBoy指向第一个小孩
            }else {
                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy=boy;
            }
        }
    }
    //遍历
    public void list(){
        //判断当前链表是否为空
        if (first==null){
            System.out.println("没有任何小孩");
            return;
        }
        //因为first指针不能动,所以我们这里使用辅助指针遍历
        Boy cur=first;
        while (cur.getNext()!=first){
            System.out.printf("当前小孩编号%d\t",cur.getNo());
            cur=cur.getNext();
        }
        System.out.printf("当前小孩编号%d\t\n",cur.getNo());

    }
    //根据用户的输入,计算出小孩出圈的顺序

    /**
     * @param startNo 表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @param nums 表示最初有多小小孩在圈中
     */
    public void countBoy(int startNo,int countNum,int nums){
        //先对数据进行校验
        if (first==null||startNo<1||startNo>nums){
            System.out.println("参数输入有误,重新输入");
            return;
        }
        //创建要给辅助指针,帮助完成小孩出圈
        Boy helper=first;
        //需求创建一个辅助指针(变量)helper,事先应该指向环形链表的最后这个节点
        while (true){
            if (helper.getNext()==first){
                break;
            }
            helper=helper.getNext();
        }
        //小孩报数,先让first和helper 移动k-1次
        for(int j=0;j<startNo-1;j++){
            first=first.getNext();
            helper=helper.getNext();
        }
        //当小孩报数时,让first和helper 指针同时的移动m-1次,然后出圈
        //这里是一个循环操作,知道圈中只有一个节点
        while (true){
            if (helper==first){
                break;
            }
            //让first和helper指针同时移动countNum-1
            for (int j=0;j<countNum-1;j++){
                first=first.getNext();
                helper=helper.getNext();
            }
            System.out.printf("小孩%d出圈\n",first.getNo());
            //这时将first指向的小孩节点出圈
            first=first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留下的小孩%d\n",helper.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;
    }
}

双向链表

package linkedlist;

import java.util.LinkedList;

/**
 * @author zwf
 * @Package: linkedlist
 * @ClassName: DoubleLinkedListDemo
 * @Description:
 * @date 2022/8/28 16:32
 */
public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        DoubleLinkedList linkedList = new DoubleLinkedList();
        linkedList.add(new Hero2(1,"周文锋","文锋"));
        linkedList.add(new Hero2(2,"松江","黑脸"));
        linkedList.add(new Hero2(3,"林冲","林教头"));
        linkedList.del(3);
        linkedList.update(new Hero2(1,"zwf","zwf"));
        linkedList.list();

    }
}
//创建一个双向链表的类
class DoubleLinkedList{
    //先初始化一个头节点,头节点不要动,不存储具体数据
    private Hero2 head=new Hero2(0,"","");
    //放回头节点
    public Hero2 getHead(){
        return head;
    }
    //遍历链表
    public void list(){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("该链表为空");
            return;
        }
        Hero2 temp=head.next;
        while (true){
            if (temp==null){
                break;
            }
            System.out.println(temp);
            temp=temp.next;
        }
    }
    //修改
    public void update(Hero2 hero2){
        //判断链表是否为空
        if (head.next==null){
            System.out.println("链表为空~~");
            return;
        }
        Hero2 temp =head.next;
        boolean flag=false;
        while (temp!=null){
            if (temp.no==hero2.no){
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){
            temp.name= hero2.name;
            temp.niceName=hero2.niceName;
        }else {
            System.out.println("没有找到该编号的链表");
        }

    }
    //添加元素
    public void add(Hero2 hero2){
        Hero2 temp=head;
        //遍历到链表尾部
        while (temp.next!=null){
            temp=temp.next;
        }
        temp.next=hero2;
        hero2.pre=temp;
    }
    //删除
    public void del(int no){
        Hero2 temp=head.next;
        while (temp!=null){
            //查找到当前元素
            if (temp.no==no){
                temp.pre.next=temp.next;
                if (temp.next!=null){//最后一个元素
                    temp.next.pre=temp.pre;
                }
                break;
            }
            temp=temp.next;
        }
    }
}
class Hero2{
    public int no;
    public String name;
    public String niceName;
    public Hero2 next;
    public Hero2 pre;
    public Hero2(int no,String name,String niceName){
        this.no=no;
        this.name=name;
        this.niceName=niceName;
    }

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

  • 栈英文为(stack)
  • 栈是一个先入后出的有序列表
  • 栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom).
  • 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素·最先删除,最先放入的元素最后删除
package steck;

/**
 * @author zwf
 * @Package: steck
 * @ClassName: ArraySteckDemo
 * @Description:
 * @date 2022/9/2 13:44
 */
public class ArraySteckDemo {
    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(5);
        arrayStack.push(1);
        arrayStack.push(2);
        arrayStack.push(3);
        arrayStack.push(4);
        arrayStack.push(5);
        arrayStack.list();
        System.out.println(arrayStack.pop());
        arrayStack.list();
    }
}
/**
 * 栈的思路分析
 * 1,使用数组来模拟栈
 * 2.定义一个top来表示栈顶,初始化为-1
 * 3.入栈的操作,当有数据加入到栈时,top++;stack[top]=data
 * 4.出栈的操作,int value=stack[top];top--,return valuel
 */
//定义一个ArrayStack表示栈
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 data){
        //判断栈是否满
        if (isFull()){
            System.out.println("栈满了~");
            return;
        }
        stack[++top]=data;
    }
    //出栈
    public int pop(){
        //判断栈是否为空
        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]);
        }
    }

}

栈实现综合计算器

package steck;

/**
 * @author zwf
 * @Package: steck
 * @ClassName: 实现计算器
 * @Description:
 * @date 2022/9/2 18:35
 */

/**使用栈完成表达式的计算思路
 *1.通过一个index值(索引),来遍历我们的表达式
 * 2.如果我们发现是一个数字,将直接入数栈
 * 3.如果发现扫描到是一个符号,就分如下情况
 *  3.1 如果发现符号栈为空,就直接入栈
 *  3,2如果符号栈有操作符,就进行比较,如果当前操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,在从符号栈pop
 *  出一个字符,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈,如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈
 *  4.当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行
 *  5,最后在数栈只有一个数字,就是表达式的结果
 */
public class 实现计算器 {
    public static void main(String[] args) {
        String expression="100+2*6-12";
        //创建两个栈
        ArrayStack1 numStack=new ArrayStack1(10);
        ArrayStack1 operStack=new ArrayStack1(10);
        //定义需要的相关变量
        int index=0;//用于扫描
        int num1=0;
        int num2=0;
        int oper=0;
        int res=0;
        String keepNum="";//用于拼接多位数
        char ch;//将每次扫描得到char保存到char中
        //开始while循环的扫描expression
        while (true){
            ch=expression.charAt(index);
            //判断ch是什么,然后做相应的处理
            if (operStack.isOper(ch)){ //如果是运算符
                //判断当前的符号栈是否为空
                if (!operStack.isEmpty()){
                    //如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,
                    //在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,当前的操作符入符号栈
                    if (operStack.priority(ch)<= operStack.priority(operStack.peek())){
                        num1=numStack.pop();
                        num2=numStack.pop();
                        oper=operStack.pop();
                        res=numStack.cal(num1,num2,oper);
                        //把运算的结果入数栈
                        numStack.push(res);
                    }
                    //然后将当前操作符入符号栈
                    operStack.push(ch);
                }else {
                    //如果为空则直接入符号栈
                    operStack.push(ch);
                }
            }else {
                //如果是数字直接入数字栈
//                numStack.push(Integer.parseInt(String.valueOf(ch)));
//                numStack.push(ch-48);
                /*思路分析
                * 1.当处理多位数时,不能发现是一个数就立刻入栈,因为他可能是多位数
                * 2.在处理数,需要向expression的表达式的index后再看一位,如果是数就进行扫描,如果是符号才入栈
                * 3.因此我们需要定义一个变量字符串,用于拼接
                * */
                keepNum+=ch;
                if (index==expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));
                }else {
                    if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
                        numStack.push(Integer.parseInt(keepNum));
                        //使用完keepNum变量记得清空
                        keepNum="";
                    }
                }

            }
            index++;
            //判断expression是否遍历完成
            if (index>=expression.length()){
                break;
            }
        }
        //当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相应的数和符号,并运行
        while(true){
            if (operStack.isEmpty()){
                break;
            }
            num1=numStack.pop();
            num2=numStack.pop();
            oper=operStack.pop();
            res=numStack.cal(num1,num2,oper);
            numStack.push(res);
        }
        System.out.printf("表达式%s=%d",expression,numStack.pop());

    }
}
//定义一个ArrayStack表示栈
class ArrayStack1 {
    private int maxSize;//栈的大小
    private int[] stack;//数组,数组模拟栈,数据就放在该数组
    private int top = -1;

    public ArrayStack1(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];
    }
    //可以返回当前栈顶的值
    public int peek(){
        return stack[top];
    }
    //栈满
    public boolean isFull() {
        return top == maxSize - 1;
    }

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

    //入栈
    public void push(int data) {
        //判断栈是否满
        if (isFull()) {
            System.out.println("栈满了~");
            return;
        }
        stack[++top] = data;
    }

    //出栈
    public int pop() {
        //判断栈是否为空
        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;//res用于存放计算的结果
        switch (oper){
            case '+':
                res=num1+num2;
                break;
            case '-':
                res=num1-num2;
                break;
            case '*':
                res=num2*num1;
                break;
            case '/':
                res=num2/num1;
                break;
            default:
                break;
        }
        return res;
    }
}


逆波兰计算器

package steck;

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

/**
 * @author zwf
 * @Package: steck
 * @ClassName: PolandNotation
 * @Description:
 * @date 2022/9/3 13:57
 */
public class PolandNotation{
    public static void main(String[] args){
        /**
         * 中缀表达式"1+((2+3)*4)-5" => 后缀表达 123+4*+5-
         */
        String expression="10+((2+3)*4)-5";
        List<String> infixExpressionList = toInfixExpressionList(expression);
        System.out.println("中缀表达式对应的list"+infixExpressionList);
        List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
        System.out.println("后缀表达式对应的list"+suffixExpreesionList);
        String calculate = calculate(suffixExpreesionList);
        System.out.println(calculate);
    }
    public static String calculate(List<String> ls){
        //创建栈
        Stack<String> stack = new Stack<>();
        //遍历
        for (String l : ls) {
            //这里使用正则表达式来取值
            if (l.matches("\\d+")){
                stack.push(l);
            }else {
                //pop 出两个数,并运算,再入栈
                int num2=Integer.parseInt(stack.pop());
                int num1=Integer.parseInt(stack.pop());
                int res=0;
                if (l.equals("+")){
                    res=num1+num2;
                }else if (l.equals("-")){
                    res=num1-num2;
                }else if (l.equals("*")){
                    res=num1*num2;
                }else if (l.equals("/")){
                    res=num1/num2;
                }else {
                    throw new RuntimeException("运算符有误");
                }
                stack.push(""+res);
            }
        }
        return stack.pop();
    }
    //中缀转对应的list
    public static List<String> toInfixExpressionList(String s){
        //定义一个list,存放后缀表达式
        ArrayList<String> ls = new ArrayList<>();
        int i=0;//这时是一个指针,用于遍历中缀表达式字符串
        String str;//对多为数的拼接
        char c;//每遍历到一个字符,就放入到c
        do{
            //如果c是一个非数字,我需要加入到ls
            if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){
                ls.add(""+c);
                i++;
            }else {
                //如果是一个数,需要考虑多位数
                str="";
                while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
                    str+=c;//拼接
                    i++;
                }
                ls.add(str);
            }
        }while (i<s.length());

        return ls;
    }


    /**将得到的中缀表达式对应的list=》后缀表达式对应的list
     *即 ArrayList【1,+,(,(,2,+,3,),*,4,),-,5] => [1,2,3,+,4,*,5,-]
     *思路分析
     * 1.初始化两个栈:运算符栈s1和存储中间结果的栈s2
     * 2.从左至右扫描中缀表达式;
     * 3.遇到操作数时,将其压s2;
     * 4.遇到运算符时,比较其与s1栈顶运算符的优先级:
     * 4.1 如果s1为空,或者栈顶运算符为左括号"(",则直接将此运算符入栈;
     * 4.2否则,若优先级比栈顶运算符的高,也将运算符压入s1
     * 4.3 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符比较;
     * 5.遇到括号时:
     * (1)如果是左括号”(“,则直接压入s1
     *  (2)如果是右括号”)“,则依次弹出s1栈顶的运算符,并压入s2.直到遇到左括号为止,止时一对括号丢弃
     *  6.重复步骤2到5,直到表达式的最右边
     *  7.将s1中剩余的运算符依次弹出并压入s2
     *  8.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
     */
    public static List<String> parseSuffixExpreesionList(List<String> ls){
        //初始化两个栈
        Stack<String> s1 = new Stack<>();
        //因为s2这个栈,在整个转换过程中没有pop操作,而且我们后面还需要逆序输出使用list比较方便
        List<String> s2=new ArrayList<>();
        //遍历ls
        for (String item : ls) {
            //遇到操作数时,将其压s2
            if (item.matches("\\d+")){
                s2.add(item);
            }else if (item.equals("(")){
                //如果是左括号”(“,则直接压入s1
                s1.push(item);
            }else if (item.equals(")")){
                //如果是右括号”)“,则依次弹出s1栈顶的运算符,并压入s2.直到遇到左括号为止,止时一对括号丢弃
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//将(弹出s1栈,消除小括号
            }else{
                //item的优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次栈到(4.1)与s1中新的栈顶运算符相比较
                while (s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //还需要将item压入栈
                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:
                break;
        }
        return res;
    }
}

递归

八皇后问题

package recursion;

/**
 * @author zwf
 * @Package: recursion
 * @ClassName: 八皇后问题
 * @Description:
 * @date 2022/9/14 19:33
 */
public class 八皇后问题 {
    //定义一个max表示共有多小个皇后
    int max=8;
    //定义数组array,保存皇后放置位置的结果,比如arr={0,4,7,5,2,6,1,3}
    int[] array=new int[max];
    int count=0;
    public static void main(String[] args) {
        八皇后问题 八皇后问题 = new 八皇后问题();
        八皇后问题.check(0);
        System.out.println(八皇后问题.count);
    }
    //编写一个方法,放置第n个皇后
    private void check(int n){
        if (n==max){//n=8,此时8个皇后就放好
            print();
            return;
        }
        //依次放入皇后,并判断是否冲突
        for (int i=0;i<max;i++){
            //先把当前这个皇后n,放到该行第一列
            array[n]=i;
            if (judge(n)){
                check(n+1);
            }
        }
    }
    //查看当前我们放置第n个皇后,就去检测皇后是否和前面
    private boolean judge(int n){
        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皇后在同一斜线
             */
            if (array[i]==array[n]||Math.abs(n-i)==Math.abs(array[n]-array[i])){
                return false;
            }
        }
        return true;
    }
    //写一个方法,可以将皇后摆放的位置输出
    public void print(){
        count++;
        for (int i=0;i<array.length;i++){
            System.out.print(array[i]+" ");
        }
        System.out.println();
    }
}

迷宫回溯

package recursion;

/**
 * @author zwf
 * @Package: recursion
 * @ClassName: migong
 * @Description:
 * @date 2022/9/13 18:09
 */
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;
        }
        //左右全部置为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[2][2]=1;
        map[1][2]=1;
        //输出地图
        System.out.println("地图的情况");
        for (int i=0;i<8;i++){
            for (int j=0;j<7;j++){
                System.out.printf(map[i][j]+" ");
            }
            System.out.println();
        }
        //使用递归回溯
        setWay(map,1,1);
        //输出新地图
        System.out.println("新地图的情况");
        for (int i=0;i<8;i++){
            for (int j=0;j<7;j++){
                System.out.printf(map[i][j]+" ");
            }
            System.out.println();
        }

    }
    /**
     * 使用递归回溯来给小球找路
     *  说明
     *  1.map表示地图
     *  2.i,j表示从地图的哪个位置开始出发(1,1)
     *  3.如果小球能到map[6][5]位置,则说明通路找到。
     *  4.约定:当map[i][j]为0表示该点没有走过 当为1表示墙;2表示通路可以走;3表示该点已经走过,但是走不通
     *  5.在走迷宫时,需要确定一个策略,下->右->上->左
     */
    /**
     * @param map 表示地图
     * @param i 从那个位置开始栈
     * @param j
     * @return 如果找到通路,就返回true,否则返回false
     */
    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 {//如果map[i][j]!=0,可能是1,2,3
                return false;
            }
        }
    }
}

递归执行流程

package recursion;

/**
 * @author zwf
 * @Package: recursion
 * @ClassName: demo01
 * @Description:
 * @date 2022/9/4 17:32
 */
public class demo01 {
    public static void main(String[] args) {
        t(5);
    }
    public static void t(int n){
        if (n>2){
            System.out.printf(n+"\t");
            t(n-1);
        }
        System.out.println("n="+n);
    }
}

排序算法

  • 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程

image-20220916113245941转存失败,建议直接上传图片文件

冒泡排序

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: 冒泡排序
 * @Description:
 * @date 2022/9/16 12:12
 */
public class 冒泡排序 {
    public static void main(String[] args) {
        int arr[]={3,9,-2,20,-2};
        bubbleSort(arr);
    }
    public static void bubbleSort(int[] arr){
        //冒泡排序 的时间复杂度O(n^2)
        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){
                flag=false;//重置
            }else {
                break;//在一趟排序中。一次交换都没有发生过
            }
        }
    }
}

冒泡排序类

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: Bubble
 * @Description: 冒泡排序
 * @date 2022/11/16 12:45
 */
public class Bubble {
    /*
    对数组a中的元素进行排序
     */
    public static void sort(Comparable[] arr){
        for (int i=0;i<arr.length-1;i++){
            boolean falg=false;
            for (int j=0;j<arr.length-i-1;j++){
                if (greater(arr[j],arr[j+1])){
                    falg=true;
                    exch(arr,j,j+1);
                }
            }
            System.out.println("第"+i+"次排序"+ Arrays.toString(arr));
            if (!falg){
                System.out.println("第"+i+"次排序后停止"+ Arrays.toString(arr));
                break;
            }
        }
    }
    /*
    比较v元素是否大于w元素
     */
    private static boolean greater(Comparable v,Comparable w){
        return v.compareTo(w)>0;
    }
    /*
    数组元素i和j交换位置
     */
    private static void exch(Comparable[] arr,int i ,int j){
        Comparable temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

测试:

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: BubbleTest
 * @Description:
 * @date 2022/11/16 12:59
 */
public class BubbleTest {
    public static void main(String[] args) {
        Integer[] arr={1,5,3,65,23,24};
        Bubble.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

image-20221116130630407转存失败,建议直接上传图片文件

选择排序

  • 选择式排序也属于内部排序法,是从欲排序的数据中,按指定的规矩选出某一元素,再依次交换位置后达到排序的目的。
package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: 选择排序
 * @Description:
 * @date 2022/9/16 15:56
 */
public class 选择排序 {
    public static void main(String[] args) {
        int [] arr={1,-2,-3,7,19,23};
        int temp=0;
        for (int j=0;j<arr.length-1;j++){
            for (int i = 1+j; i < arr.length; i++) {
                if (arr[j]>arr[i]){
                    temp=arr[j];
                    arr[j]=arr[i];
                    arr[i]=temp;
                }
            }
            System.out.println("第"+(j+1)+"趟排序后的数组");
            System.out.println(Arrays.toString(arr));
        }
    }
}

方式二

    /**
     * 选择排序
     * @param arr
     * @return
     */
    public static void select(int[] arr){
        /*
        思路:  int[] arr={100,2,8,10,5,99};
        1.0-n-1
        2.1-n-1
        3.2-n-1
         */
        int N=arr.length;
        for (int i=0;i<N-1;i++){
            int minValueIndex=i;
            for (int j=i+1;j<N;j++){
                minValueIndex=arr[minValueIndex]>arr[j]?j:minValueIndex;
            }
            wasp(arr,minValueIndex,i);
        }
    }

选择排序类

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: Bubble
 * @Description: 选择排序
 * @date 2022/11/16 12:45
 */
public class Selection {
    /*
    对数组a中的元素进行排序
     */
    public static void sort(Comparable[] arr){
       int N=arr.length;
       for (int i=0;i<N-1;i++){
           int minvalueIndex=i;
           for (int j=i+1;j<N;j++){
               minvalueIndex=greater(arr[minvalueIndex],arr[j])? j:minvalueIndex;
           }
           exch(arr,minvalueIndex,i);
       }
    }
    /*
    比较v元素是否大于w元素
     */
    private static boolean greater(Comparable v,Comparable w){
        return v.compareTo(w)>0;
    }
    /*
    数组元素i和j交换位置
     */
    private static void exch(Comparable[] arr,int i ,int j){
        Comparable temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

插入排序

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: 插入排序
 * @Description:
 * @date 2022/9/16 21:00
 */
public class 插入排序 {
    public static void main(String[] args) {
        int arr[]={1,9,0,-7,9,20};
        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;//即arr[1]前面这个数的下标
            //给insetVal找到插入位置
            /**说明
             * 1.insertIndex>=0; 保证在给inserVal找到插入位置,不越界
             * 2.insertVal<arr[insertIndex]待插入的数,还没有找到插入位置
             * 3.就需要将arr【inserIndex】后移
             */
            while (insertIndex>=0&&insertVal<arr[insertIndex]){
                arr[insertIndex+1]=arr[insertIndex];
                insertIndex--;
            }
            //当退出while循环时,说明插入的位置找到,inserIndex+1
            if (insertIndex+1!=i){//说明移动了
                arr[insertIndex+1]=insertVal;
            }
            System.out.println("第"+i+"轮插入");
            System.out.println(Arrays.toString(arr));
        }
    }
}

简化版

package 排序;

import sun.rmi.runtime.NewThreadAction;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: 排序
 * @ClassName: 插入排序
 * @Description:
 * @date 2022/9/17 21:55
 */
public class 插入排序 {
        //核心代码---开始
        public static void sort(int[] arr){
            int n = arr.length;
            for (int i = 0; i < n; i++) {
                // 寻找元素 arr[i] 合适的插入位置
                for( int j = i ; j > 0 ; j -- )
                    if( arr[j]<arr[j-1])
                        swap( arr, j , j-1 );
                    else
                        break;
            }
        }
        //核心代码---结束
        private static void swap(int[] arr, int i, int j) {
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }

        public static void main(String[] args) {
            int[] arr = {1,-2,4,-6,10};
            sort(arr);
            for( int i = 0 ; i < arr.length ; i ++ ){
                System.out.print(arr[i]);
                System.out.print(' ');
            }
        }

}

方法三

/**
     * 插入排序
     * @param arr
     */
    public static void insertSort(int[]arr){
        for (int i=1;i<arr.length;i++){//排序五次
           for (int j=i-1;j>=0&&arr[j]>arr[j+1];j--){
               wasp(arr,j,j+1);
           }
        }
    }

插入排序类

package Sort;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: Insertion
 * @Description: 插入排序
 * @date 2022/11/16 18:36
 */
public class Insertion {
    /*
   对数组a中的元素进行排序
    */
    public static void sort(Comparable[] arr){
        for (int i=0;i<arr.length-1;i++){
            for (int j = i; j > 0; j--) {
                if (greater(arr[j-1],arr[j])){
                    exch(arr,j,j-1);
                }else {
                    break;
                }
            }
        }
    }
    /*
    比较v元素是否大于w元素
     */
    private static boolean greater(Comparable v,Comparable w){
        return v.compareTo(w)>0;
    }
    /*
    数组元素i和j交换位置
     */
    private static void exch(Comparable[] arr,int i ,int j){
        Comparable temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

希尔排序

package Sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: ShellSort
 * @Description:
 * @date 2022/9/17 14:01
 * 希尔排序
 */
public class ShellSort {
    public static void main(String[] args) {
//            int[] arr={8,9,1,7,2,3,5,4,6,0};
        int[] arr=new int[80000];
        for(int i=0;i<arr.length;i++){
            arr[i]=(int)(Math.random()*800000);
        }
        System.out.println("排序前");
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("排序前的时间是"+simpleDateFormat.format(System.currentTimeMillis()));
//        shellSort(arr); //交换法
        shellSort2(arr);//移位方式
        System.out.println("排序后的时间是"+simpleDateFormat.format(System.currentTimeMillis()));
//        System.out.println(Arrays.toString(arr));
    }
    /**
     * 使用逐步推导的方式来编写希尔排序
     */
    public static void shellSort(int[] arr){
        int temp=0;
        int count=0;
        //根据前面的逐步分析,使用循环处理
        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;
                    }
                }
            }
        }
    }
    /**
     * 对交换式的希尔排序进行优化->移位法
     */
    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 index=i;
                int temp=arr[index];
                if (arr[index]<arr[index-gap]){
                    while (index-gap>=0&&temp<arr[index-gap]){
                        //移动
                        arr[index]=arr[index-gap];
                        index-=gap;
                    }
                    arr[index]=temp;
                }
            }
        }
    }
}


希尔排序类

package Sort;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: Insertion
 * @Description: 插入排序
 * @date 2022/11/16 18:36
 */
public class Shell {
    /*
   对数组a中的元素进行排序 优化位移法
    */
    public static void sort(Comparable[] arr){
       for (int gap=arr.length/2;gap>0;gap/=2){
           for (int i=gap;i<arr.length;i++){
               int index=i;
               Comparable temp=arr[index];
               if (greater(arr[index-gap],arr[index])){
                   while (index-gap>=0&&greater(arr[index-gap],temp)){
                       arr[index]=arr[index-gap];
                       index=index-gap;
                   }
                   arr[index]=temp;
               }
           }
       }
    }
    /*
 对数组a中的元素进行排序
  */
    public static void sort1(Comparable[] arr){
        for (int gap=arr.length/2;gap>0;gap/=2){
           for (int i=gap;i<arr.length;i++){
               for (int j=i-gap;j>=0;j-=gap){
                   if (greater(arr[j],arr[j+gap])){
                       exch(arr,j,j+gap);
                   }
               }
           }
        }
    }
    /*
对数组a中的元素进行排序
*/
    public static void sort2(Comparable[] arr){
        //1.根据数组arr的长度,确定增长量h的初始值
        int h=1;
        while (h<arr.length/2){
            h=2*h+1;
        }
        //2.希尔排序
        while (h>=1){
            //2.1找到插入元素
            for (int i=h;i< arr.length;i++){
                for (int j=i;j>=h;j-=h){
                    if (greater(arr[j-h],arr[j])){
                        exch(arr,j-h,j);
                    }else {
                        break;
                    }
                }
            }
            h/=2;
        }
    }
    /*
    比较v元素是否大于w元素
     */
    private static boolean greater(Comparable v,Comparable w){
        return v.compareTo(w)>0;
    }
    /*
    数组元素i和j交换位置
     */
    private static void exch(Comparable[] arr,int i ,int j){
        Comparable temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
}

快速排序

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: QuickSort
 * @Description:
 * @date 2022/9/17 20:02
 */
public class QuickSort {
    public static void main(String[] args) {
        int[] arr={-9,78,0,23,-567,70};
        quickSort(arr,0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static void quickSort(int[] arr,int left,int right){
        int l=left;
        int r=right;
        //pivot中轴
        int pivot=arr[(left+right)/2];
        int temp=0;
        //while循环目的是让比pivot值小放到左边比pivot值大放到右边
        while (l<r){
            while (arr[l]<pivot){
                l=l+1;
            }
            while (arr[r]>pivot){
                r=r-1;
            }
            /*
            如果l>=r说明pivot的左右两的值。已经按照左边全部是小于
            等于pivot值。右边全部都是大于等于pivot值
             */
            if (l>=r){
                break;
            }
            //交换
            temp=arr[l];
            arr[l]=arr[r];
            arr[r]=temp;
            //如果交换完后,发现这个arr【l】==privot 相等r--,前移
            if (arr[l]==pivot){
                r-=1;
            }
            //如果交换完后,发现这个arr[r]==pivot值 相等l++,后移
            if(arr[r]==pivot){
                l+=1;
            }
        }
        //如果l==r,
        if (l==r){
            l+=1;
            r-=1;
        }
//        //向左递归
        if (left<r){
            quickSort(arr, left, r);
        }
        //向右递归
        if (right>l){
            quickSort(arr, l, right);
        }
    }
}

以第一个数为基数

package Sort;

import java.util.Arrays;

/**
 * @author zwf
 * @Package: Sort
 * @ClassName: QuickSory
 * @Description: 快速排序
 * @date 2022/9/17 20:47
 */
public class QuickSort02 {
    public static void main(String[] args) {
        int[] arr={-9,78,0,23,-567,70};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static void quickSort(int[] arr,int start,int end){
        if (start>end){
            return;
        }
        int i,j,base;
        i=start;
        j=end;
        base=arr[start];
        while (i<j){
            while (i<j&&arr[j]>=base){
                j--;
            }
            while (i<j&&arr[i]<=base){
                i++;
            }
            if (i<j){
                swap(arr, i, j);//交换
            }
        }
        swap(arr,start,i);
        //左递归
        quickSort(arr, start, j-1);
        //右递归
        quickSort(arr, j+1, end);
    }
    //交换
    public static void  swap(int[] nums,int left,int right){
        int temp=nums[left];
        nums[left]=nums[right];
        nums[right]=temp;
    }
}

归并排序

随机函数Math.random的使用

从1-5随机到1-7

package 二进制;

/**
 * @author zwf
 * @Package: 二进制
 * @ClassName: demo02
 * @Description:
 * @date 2022/9/22 14:10
 */

/**
 * 从1-5随机到1-7
 *
 */
public class demo02 {
    public static void main(String[] args) {
        for (int i=100;i>=0;i--){
            System.out.print(f3()+" ");
        }
    }

    /**
     * 随机生成1-5
     * @return
     */
    public static int f1(){
        return (int) (Math.random()*5+1);
    }

    /**
     * 随机机置只能使用f1函数
     * @return
     */
    public static  int f2(){
        int ans=0;
        do{
            ans=f1();
        }while (ans==3);
        return ans<3?0:1;
    }
    //得到000-111做到等概率
    public static int f3(){
        int ans=(f2()<<2)+(f2()<<1)+(f2()<<0);
        return ans;
    }
}