diff --git a/src/main/java/com/ziyu/linkedlist/DoubleLinkedListDemo.java b/src/main/java/com/ziyu/linkedlist/DoubleLinkedListDemo.java new file mode 100644 index 0000000..558dbb4 --- /dev/null +++ b/src/main/java/com/ziyu/linkedlist/DoubleLinkedListDemo.java @@ -0,0 +1,190 @@ +package com.ziyu.linkedlist; + +public class DoubleLinkedListDemo { + + + public static void main(String[] args) { + //进行测试 + //先创建节点 + HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨"); + HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟"); + HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星"); + HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头"); + HeroNode2 hero5 = new HeroNode2(4, "林冲2", "豹子头2"); + DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); +// DoubleLinkedList doubleLinkedList2 = new DoubleLinkedList(); + doubleLinkedList.add(hero1); + doubleLinkedList.add(hero2); + doubleLinkedList.add(hero3); + doubleLinkedList.add(hero4); + doubleLinkedList.list(); + + System.out.println("-----"); + doubleLinkedList.update(hero5); + doubleLinkedList.list(); + + doubleLinkedList.delete(4); + System.out.println("-----"); + doubleLinkedList.list(); + + } +} + +class DoubleLinkedList { + //初始化头结点,不存数据 + HeroNode2 head = new HeroNode2(0, "", ""); + + //返回头结点 + public HeroNode2 getHead() { + return head; + } + + + //遍历链表的节点的信息 + 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; + } + } + + + //添加节点 双向链表的尾部 + public void add(HeroNode2 node) { + + //引入一个辅助节点 + HeroNode2 temp = head; + + while (true) { + + //当temp的下一个节点为空的时候,则退出 + if (temp.next == null) { + break; + } + temp = temp.next;//链表后移动 + } + //循环结束,将新节点放到尾部即可 + temp.next = node; + node.pre = temp; + } + + + //修改节点,除编号之外的内容 + public void update(HeroNode2 node) { + if (head.next == null) { + System.out.println("链表为空!"); + return; + } + + if (node == null) { + System.out.println("新节点内容为空!"); + return; + } + + HeroNode2 temp = head; + boolean flag = false; + while (true) { + + //到达链表的尾部,退出即可。 + if (temp.next == null) { + break; + } + + if (temp.next.no == node.no) { + //找到了该节点的内容 + flag = true; + break; + } + temp = temp.next; + } + + if (flag) { + //找到该节点修改内容即可 + temp.next.name = node.name; + temp.next.nikename = node.nikename; + } else { + //没找到要修改的节点 + System.out.println("没有找到要修改的节点的内容。"); + return; + } + } + + /** + * 双链表可以找到自己的这个节点,然后删除即可。 + * + * @param no + */ + public void delete(int no) { + if (head.next == null) { + System.out.println("该链表为空!,无法删除"); + return; + } + + HeroNode2 curr = head.next; //哨兵 + boolean flag = false; //默认没找到 + + while (true) { + if (curr == null) { + break; + } + if (curr.no == no) { + flag = true; + break; + } + curr = curr.next; + } + + if (flag) { + //找到了要删除的节点,删除即可 + curr.pre.next = curr.next; + + //代码有风险,如果删除的是最后一个节点就是 curr.next = null + if (curr.next != null) { + curr.next.pre = curr.pre; + } + } else { + System.out.println("没有找到该节点!"); + return; + } + + } + + +} + +class HeroNode2 { + + public int no; + public String name; + public String nikename; + public HeroNode2 next; //默认为null + public HeroNode2 pre; //默认为null + + public HeroNode2(int no, String name, String nikename) { + this.no = no; + this.name = name; + this.nikename = nikename; + } + + @Override + public String toString() { + return "DoubleLinkedList{" + + "no=" + no + + ", name='" + name + '\'' + + ", nikename='" + nikename + '\'' + + '}'; + } + +} \ No newline at end of file diff --git a/src/main/java/com/ziyu/linkedlist/JosepfuDemo.java b/src/main/java/com/ziyu/linkedlist/JosepfuDemo.java new file mode 100644 index 0000000..2501c00 --- /dev/null +++ b/src/main/java/com/ziyu/linkedlist/JosepfuDemo.java @@ -0,0 +1,189 @@ +package com.ziyu.linkedlist; + +public class JosepfuDemo { + + public static void main(String[] args) { + + + //测试一把,看看环形链表是否正确 + CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); + circleSingleLinkedList.addBoy(5); + circleSingleLinkedList.showBoy(); + System.out.println(); + //小孩子出圈是否正确 + circleSingleLinkedList.countBoy2(1, 2, 5); + + + } +} + +class CircleSingleLinkedList { + + //创建一个First节点 + private Boy first = null; + + + //添加小孩,构建环形链表 + public void addBoy(int nums) { + //nums 校验 + if (nums < 1) { + System.out.println("nums的值不正确"); + return; + } + + Boy currBoy = null; //辅助变量,帮助构建环形链表 + //for循环创建一个链表 + for (int i = 1; i <= nums; i++) { + //根据编号创建小孩节点 + Boy boy = new Boy(i); + //如果是第一个小孩,要特殊处理 + if (i == 1) { + first = boy; + first.next = first; //自己指向自己 + currBoy = first; //辅助变量指向第一个小孩子 + } else { + currBoy.next = boy; + boy.next = first; + currBoy = boy;//curr 指向下一个新节点 + } + } + } + + + public void showBoy() { + //判断是不是为空 + if (first == null || first.next == null) { + System.out.println("链表为空!"); + return; + } + + //first指针不能动记录第一个,需要一个辅助指针遍历 + Boy currBoy = first; + + while (true) { + System.out.printf("小孩子的编号%d \n", currBoy.no); + if (currBoy.next == first) { + break; + } else { + currBoy = currBoy.next; + } + } + } + + //根据用户的输入,计算出小孩子出圈的顺序 + + /** + * @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; + //确定第一个节点和最后一个节点 + while (true) { + if (helper.next == first) { + break; + } + helper = helper.next; + } + + //小哈子报数前,先让first 和 helper 移动k-1次 + for (int j = 0; j < startNo - 1; j++) { + first = first.next; + helper = helper.next; + } + + //出圈 + while (true) { + //说明圈中只有一个节点 + if (helper == first) { + break; + } + //移动 m-1 次 first and helper 移动 countNum-1 + for (int j = 0; j < countNum - 1; j++) { + first = first.next; + helper = helper.next; + } + //此时的first节点就是要出圈的节点 + System.out.printf("小孩子的%d出圈\n", first.no); + first = first.next; + //指针移动跳过去出圈的小孩子 + helper.next = first; + } + + System.out.printf("最终留在圈中的小孩子是%d\n", first.no); + } + + /** + * @param startNo 起始数字 + * @param countNum 步长 喊道几,几出圈 + * @param num 总共几个 + */ + public void countBoy2(int startNo, int countNum, int num) { + + if (first == null || startNo < 1 || startNo > num) { + System.out.println("输入有误!"); + return; + } + + //定义辅助节点helper + Boy helper = first; + + //第一次遍历,找到helper的位置 helper 放到first之前。 + while (true) { + if (helper.next == first) { + break; + } + helper = helper.next; + } + + //第一次helper和 first 都要移动 startNo-1次 + for (int j = 0; j < startNo - 1; j++) { + first = first.next; + helper = helper.next; + } + + //出圈,first 走在前面,helper走后面记录下次报数的位置 + while (true) { + + if (helper == first) { + break; //最后一个 + } + for (int j = 0; j < countNum - 1; j++) { + first = first.next; + helper = helper.next; + } + System.out.println("这次出圈的数字为:" + first.no); + first = first.next; + helper.next = first; + } + System.out.println("最后的幸运儿为:" + first.no); + } + +} + +//创建boy类,表示节点 +class Boy { + public int no; + public Boy next; + + public Boy(int no) { + this.no = no; + } + + @Override + public String toString() { + return "Boy{" + + "no=" + no + + '}'; + } +} + + diff --git a/src/main/java/com/ziyu/linkedlist/test/SingleLinkedListTestDemo.java b/src/main/java/com/ziyu/linkedlist/test/SingleLinkedListTestDemo.java new file mode 100644 index 0000000..df53e5e --- /dev/null +++ b/src/main/java/com/ziyu/linkedlist/test/SingleLinkedListTestDemo.java @@ -0,0 +1,347 @@ +package com.ziyu.linkedlist.test; + + +import java.util.Stack; + +public class SingleLinkedListTestDemo { + + public static void main(String[] args) { + //进行测试 + //先创建节点 + Node hero1 = new Node(1, "宋江", "及时雨"); + Node hero2 = new Node(2, "卢俊义", "玉麒麟"); + Node hero3 = new Node(3, "吴用", "智多星"); + Node hero4 = new Node(4, "林冲", "豹子头"); + Node hero5 = new Node(4, "林冲2", "豹子头2"); + + //创建链表 + SingleList singleLinkedList = new SingleList(); + //加入 √ +// singleLinkedList.add(hero1); +// singleLinkedList.add(hero4); +// singleLinkedList.add(hero2); +// singleLinkedList.add(hero3); + singleLinkedList.addByNumber(hero1); + singleLinkedList.addByNumber(hero4); + singleLinkedList.addByNumber(hero2); + singleLinkedList.addByNumber(hero3); + + //展示链表 √ + System.out.println("--------------------------原始的链表--------------------------"); + singleLinkedList.update(hero5); + singleLinkedList.delete(4); //删除节点测试。 + singleLinkedList.list(); + + + System.out.println("该链表的长度为:" + singleLinkedList.getLinkNodeCount(singleLinkedList.getHead())); + System.out.println("倒数第二个:" + singleLinkedList.findLastIndexNode(singleLinkedList.getHead(), 2)); + System.out.println("反转之后的链表:"); + singleLinkedList.reverList(singleLinkedList.getHead()); + singleLinkedList.list(); + System.out.println("--------------"); + singleLinkedList.reverPrint(singleLinkedList.getHead()); + + } + + +} + +//定义单链表 +class SingleList { + + //定一个头节点 + Node head = new Node(0, "", ""); + + //返回头节点 + public Node getHead() { + return head; + } + + //添加节点 + public void add(Node node) { + + //引入一个辅助节点 + Node temp = head; + + while (true) { + + //当temp的下一个节点为空的时候,则退出 + if (temp.next == null) { + break; + } + temp = temp.next;//链表后移动 + } + //循环结束,将新节点放到尾部即可 + temp.next = node; + } + + //按照编号添加,如果有这个排名,则是失败,没有的话,则找到合适的位置添加即可。 + public void addByNumber(Node node) { + + //由于头节点不能动,我们需要引入一个哨兵节点 + Node temp = head; + boolean flag = false; //标示这个节点是否存在,如果存在,则为true,默认为flase + while (true) { + + if (temp.next == null) { //到达了链表的尾部 + break; + } + + //找到了,位置,添加即可。 + if (temp.next.no > node.no) { + break; + } else if (temp.next.no == node.no) { + flag = true; + System.out.println("编号已经存在了!"); + break; + } + temp = temp.next; //移动到下一个 + } + if (flag) { //编号已经存在,则不需要添加了。 + System.out.println("编号已经存在了!,编号是:" + node.no); + return; + } else { + //编号不存在,则需要添加即可 必须要新的节点指向我们temp.next 否则就会指向自己了。 + node.next = temp.next; + temp.next = node; + } + } + + //修改节点,除编号之外的内容 + public void update(Node node) { + if (head.next == null) { + System.out.println("链表为空!"); + return; + } + + if (node == null) { + System.out.println("新节点内容为空!"); + return; + } + + Node temp = head; + boolean flag = false; + while (true) { + + //到达链表的尾部,退出即可。 + if (temp.next == null) { + break; + } + + if (temp.next.no == node.no) { + //找到了该节点的内容 + flag = true; + break; + } + temp = temp.next; + } + + if (flag) { + //找到该节点修改内容即可 + temp.next.name = node.name; + temp.next.nickname = node.nickname; + } else { + //没找到要修改的节点 + System.out.println("没有找到要修改的节点的内容。"); + return; + } + } + + + public void list() { + + + if (head.next == null) { + System.out.println("链表为空!"); + return; + } + + //添加一个辅助变量,遍历链表 + Node temp = head; + + + while (true) { + + if (temp == null) { + break; + } + + System.out.println(temp); + temp = temp.next; + } + + } + + /** + * 根据传递来的no删除该节点 + * + * @param no + */ + public void delete(int no) { + if (head.next == null) { + System.out.println("该链表为空!"); + return; + } + Node 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.println("没有找到该节点!"); + return; + } + + } + + + /** + * 面试题01,求出来有效个数(不算头节点) + * + * @param head + * @return + */ + public int getLinkNodeCount(Node head) { + if (head.next == null) { + + return 0; + } + + int length = 0; + Node current = head.next; + while (current != null) { + length++; + current = current.next; + } + return length; + } + + + /** + * 返回链表第k个节点,即是index + * 遍历链表得到链表的长度,然后length-index,就是第k个节点 + */ + public Node findLastIndexNode(Node head, int index) { + if (head.next == null) { + System.out.println("空链表!"); + return null; + } + + Node cur = head.next; + boolean flag = false; + //第一次遍历得到长度 + int length = getLinkNodeCount(head); + + //第二次遍历,得到该节点,校验index + if (index > length || index <= 0) { + return null; + } + //长度为3, 找倒数第2个 + for (int i = 0; i < length - index; i++) { + + cur = cur.next; + + } + return cur; + + } + + /** + * 腾讯面试题,反转链表 + * 思路: + * 1.定一个新的节点,newHead 初始化为新节点。 + * 2.从头到尾遍历原来的链表,每遍历一个节点,取出,放到新的链表的最前端。 + * 3.将原来的头节点next指向newHead的next即可。 + * + * @param head + */ + public void reverList(Node head) { + + if (head.next == null || head.next.next == null) { + System.out.println("链表为空,不处理!"); + return; + } + + Node curr = head.next; //哨兵节点 + Node newHead = new Node(0, "", ""); //新节点,存放 + Node next = null; //用于记录当前节点的下一个 + while (curr != null) { + + // head->1->2->3->4 + // cur = head.next =1 + // reverseHead-> -> -> + next = curr.next; //记录当前节点的下一个 2 + curr.next = newHead.next; // 1next 区域执行新节点的头 + newHead.next = curr; //头指针指向当前的节点 + curr = next; //下移 + } + //原来的head的next域指向newHead next域就完成了反转 + head.next = newHead.next; + } + + /** + * 逆序打印链表 + * 1.方式一:反转链表,打印,破坏原有的结构不可取 + * 2.方式二:利用栈进行打印,先进后出即可 + */ + + + public void reverPrint(Node head) { + + if (head == null || head.next == null) { + return; + } + Stack nodeStack = new Stack<>(); + + Node curr = head.next; + while(curr!=null){ + nodeStack.push(curr); //入栈 + curr = curr.next; + } + + while(!nodeStack.empty()){ + System.out.println(nodeStack.pop()); + } + } + +} + + +//定义每一个节点的属性 每一个node都是一个对象 +class Node { + + + public int no; + public String name; + public String nickname; + public Node next; + + public Node(int no, String name, String nickname) { + this.no = no; + this.name = name; + this.nickname = nickname; + } + + @Override + public String toString() { + return "Node{" + + "no=" + no + + ", name='" + name + '\'' + + ", nickname='" + nickname + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/com/ziyu/recursion/MiGong2.java b/src/main/java/com/ziyu/recursion/MiGong2.java new file mode 100644 index 0000000..aa09fb8 --- /dev/null +++ b/src/main/java/com/ziyu/recursion/MiGong2.java @@ -0,0 +1,133 @@ +package com.ziyu.recursion; + +class MiGong2 { + + + public static void main(String[] args) { + + //模拟地图,二维数组 + int[][] map = new int[8][7]; + + //约定 1 是墙,0是可以走的路 + + //地图的上下都初始化为 1 + for (int i = 0; i < 7; i++) { + map[0][i] = 1; + map[7][i] = 1; + } + + //左右全部初始化为 1 + for (int j = 0; j < 8; j++) { + map[j][0] = 1; + map[j][6] = 1; + } + + //设置挡板 (3,1)(3,2) + map[3][1] = 1; + map[3][2] = 1; + + //新增挡板 +// map[1][2]=1; +// map[2][2]=1; + + + System.out.println("地图如下~"); + //输出地图 + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 7; j++) { + System.out.print(map[i][j] + "\t"); + } + System.out.println(); + } + + //使用递归回溯找到小球找路 + System.out.println(setWay2(map, 1, 1)); + + //输出新的地图 + System.out.println("新地图如下~"); + //输出地图 + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 7; j++) { + System.out.print(map[i][j] + "\t"); + } + System.out.println(); + } + } + + /** + * 如果能找到(6,5)就是右下角的位置就是通路 + * 0 表示这个位置还没走过,1是墙,2是可以走,3表示已经走过,但是走不通. + * 制定一个走迷宫的策略 下->右->上->左,入过该点走不通在回溯. + * + * @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 { //非0 的其他情况 + return false; + } + } + + } + + /** + * 修改策略,观察路径的情况 + * 如果能找到(6,5)就是右下角的位置就是通路 + * 0 表示这个位置还没走过,1是墙,2是可以走,3表示已经走过,但是走不通. + * 制定一个走迷宫的策略 上->右->下->左,入过该点走不通在回溯. + * + * @param map 地图 + * @param i 从哪个位置开始出发 + * @param j + * @return 找到路就是 true,找不到就是false + */ + public static boolean setWay2(int[][] map, int i, int j) { + if (map[6][5] == 2) { //右下角的位置就是终点,说明找到了. + return true; + } else { + + //按照策略找路 + if (map[i][j] == 0) { + //走迷宫的策略 下->右->上->左,入过该点走不通在回溯 + map[i][j] = 2; + if (setWay(map, i - 1, j)) { //上 + 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 { //非0 的其他情况 + return false; + } + } + + } +} diff --git a/src/main/java/com/ziyu/recursion/Queue8.java b/src/main/java/com/ziyu/recursion/Queue8.java new file mode 100644 index 0000000..bc06b39 --- /dev/null +++ b/src/main/java/com/ziyu/recursion/Queue8.java @@ -0,0 +1,69 @@ +package com.ziyu.recursion; + + +/** + * 经典8皇后问题 + */ +public class Queue8 { + //定义max最大的皇后个数 + int max = 8; + int[] array = new int[max]; //定义数组,保存皇后存放位置的结果,比如arr={0,4,7,5,2,6,1,3} + static int count = 0; + + public static void main(String[] args) { + + //测试一把,8皇后是否正确 + Queue8 queue8 = new Queue8(); + queue8.check(0); + System.out.println(count); + } + + //编写一个方法,放置第n个皇后 0,1,2,3,4,5,6,7,8 + private void check(int n) { + if (n == max) { //n=8 就放置第九个皇后了.其实8个皇后就已经放置好了. 也就是结束了. + printQueue(); + return; + } + + //以此放置皇后,判断是否冲突 + for (int i = 0; i < max; i++) { + //先把当前的皇后n,放在该行的第一列 + array[n] = i; + + //当放置第n个皇后到i列的时候,是否冲突. + if (judge(n)) {//不冲突,继续放n+1个皇后. + check(n + 1); //每一层就递归时,都会进入到for循环. + } + //如果冲突,就继续执行array[n] = i,将第n个皇后放置本行的右移的一个位置. + } + + + } + + //查看当前我们放置第n个皇后,将去监测当前皇后是否与已经摆放的冲突了 + private boolean judge(int n) { + + for (int i = 0; i < n; i++) { //第n个之前的都要监测是否冲突, 所以要for循环 + //array[i] == array[n] 是否在一列 + //Math.abs(n - i) == Math.abs(array[n] - array[i]) 是否在一个斜线上! + // n = 1 ; Math.abs(1-0) == Math.abc(array(1)-array[0]) + //没有必要判断是否在同一行, i++ 在递增 + if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) { + return false; + } + + } + return true; + } + + /** + * 打印结果. + */ + private void printQueue() { + count++; + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } +} diff --git a/src/main/java/com/ziyu/recursion/RecursionTest.java b/src/main/java/com/ziyu/recursion/RecursionTest.java new file mode 100644 index 0000000..4e14156 --- /dev/null +++ b/src/main/java/com/ziyu/recursion/RecursionTest.java @@ -0,0 +1,42 @@ +package com.ziyu.recursion; + +/** + * 递归的回顾 + */ +public class RecursionTest { + public static void main(String[] args) { + test(4); + int res = factorial(1); + System.out.println(2); + + } + + /** + * 递归打印,简单理解,入门 + * 方法栈 test(4) test(3) test(2) + * <-- < -- < -- + * 输出2,3,4 + * + * @param n + */ + public static void test(int n) { + if (n > 2) { + test(n - 1); + } + System.out.println("n:" + n); + } + + + public static int factorial(int n) { + + + if (n == 1) { + return 1; + } else { + + return factorial(n - 1) * n; + } + + } + +} diff --git a/src/main/java/com/ziyu/recursion/test/Queue8Test.java b/src/main/java/com/ziyu/recursion/test/Queue8Test.java new file mode 100644 index 0000000..a25b17a --- /dev/null +++ b/src/main/java/com/ziyu/recursion/test/Queue8Test.java @@ -0,0 +1,69 @@ +package com.ziyu.recursion.test; + +public class Queue8Test { + + static int max = 8; + static int[] array = new int[max]; + static int count = 0; + + public static void main(String[] args) { + + + Queue8Test queue8Test = new Queue8Test(); + queue8Test.put(0); + System.out.println(count); + + + } + + /** + * 监测是否冲突 + * 冲突为false 不允许放在这个位置,,不冲突为true + * + * @param n + */ + private static boolean judge(int n) { + + for (int i = 0; i < n; i++) { //第n个之前的都要判断是否冲突 + if (array[n] == array[i] || Math.abs(n - i) == Math.abs(array[n] - array[i])) { + return false; + } + //不满足需要右移 + } + return true; + + + } + + /** + * 递归回溯,找到合适的位置 + * + * @param n 放置的第n个皇后 + */ + private static void put(int n) { + if (n == max) { + printQueue(); + return; + } + + for (int i = 0; i < max; i++) { //第n个之前的位置都要判断是否冲突. + array[n] = i; //需要赋值,每一个都要涉及到 + if(judge(n)){ + put(n + 1); + } + } + } + + /** + * 打印结果 + */ + private static void printQueue() { + count++; + for (int i = 0; i < array.length; i++) { + System.out.print(array[i] + " "); + } + System.out.println(); + } + + +} diff --git a/src/main/java/com/ziyu/stack/Calculator.java b/src/main/java/com/ziyu/stack/Calculator.java new file mode 100644 index 0000000..99e783f --- /dev/null +++ b/src/main/java/com/ziyu/stack/Calculator.java @@ -0,0 +1,196 @@ +package com.ziyu.stack; + +/** + * 用栈模拟计算器 + */ +public class Calculator { + public static void main(String[] args) { + + //模拟表达式的运算 + String exprition = "700+2*6-4"; + ArrayStack2 numStack = new ArrayStack2(10); + ArrayStack2 operStack = new ArrayStack2(10); + + //定义相关的变量 + int index = 0; //扫描我们的表达式 + int num1 = 0; + int num2 = 0; + int res = 0; + int oper = 0; + char ch = ' '; //扫描的oper + String keepNum = ""; //用于拼接 多位数 + + while (true) { + //扫描exprition + ch = exprition.substring(index, index + 1).charAt(0); + if (operStack.isOper(ch)) { + if (!operStack.isEmpty()) { + //调整优先级 + if (operStack.priority(ch) <= operStack.priority(operStack.peek())) { + //弹栈,运算,入优先级小的,也就是当前的ch,保证栈顶是优先级高的先计算即可 + num1 = numStack.pop(); + num2 = numStack.pop(); + oper = operStack.pop(); + res = numStack.calc(num1, num2, oper); + //计算的新的放进去数字栈 + numStack.push(res); + + //当前的放进去 + operStack.push(ch); + } else { + operStack.push(ch); + } + } else { + //首次为空,直接入栈即可 + operStack.push(ch); + } + } else { +// numStack.push(ch - 48);//根据字符表来看,相差48 + + //上面的只能处理各位数字,下面我们要处理多位数 + keepNum += ch; //拼接下一位 + + if (index == exprition.length() - 1) { + numStack.push(Integer.parseInt(keepNum)); + }else{ + + //判断keepNum下一位是不是数字 + if (operStack.isOper(exprition.substring(index + 1, index + 2).charAt(0))) { + numStack.push(Integer.parseInt(keepNum)); + //!!!!清空keepNum + keepNum = ""; + } + } + + + } + index++; + if (index >= exprition.length()) { + break; + } + } + + //入栈完成,开始计算 + while (true) { + //如果符号栈为空,则就只有一个值了 + if (operStack.isEmpty()) { + break; + } + num1 = numStack.pop(); + num2 = numStack.pop(); + oper = operStack.pop(); + res = numStack.calc(num1, num2, oper); + //计算的新的放进去数字栈 + numStack.push(res); + } + System.out.println("表达式为:" + exprition + "=" + numStack.pop()); + } +} + +/** + * 拓展一下当前栈的功能 + */ +class ArrayStack2 { + private int maxSize; //最大值 + private int[] stack; // 数组模拟栈,数据放到数组里面 + private int top = -1; //栈顶 + + //构造器 + public ArrayStack2(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()) { + return; + } + top++; + stack[top] = value; + } + + //出栈 + public int pop() { + if (isEmpty()) { + System.out.println("栈为空"); + throw new RuntimeException("栈空了"); + } + int value = stack[top]; + top--; + return value; + } + + //遍历栈 必须从栈顶显示数据 + public void list() { + if (isEmpty()) { + System.out.println("栈为空"); + } + + 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; + } + } + + //满足就为true + public boolean isOper(char oper) { + return oper == '+' || oper == '-' || oper == '*' || oper == '/'; + } + + public int calc(int num1, int num2, int oper) { + int res = 0; + switch (oper) { //注意计算的顺序 + case '+': + res = num2 + num1; + break; + case '-': + res = num2 - num1; + break; + case '*': + res = num2 * num1; + break; + case '/': + res = num2 / num1; + break; + default: + break; + } + return res; + } + + /* + + 返回栈顶元素 + */ + public int peek() { + return stack[top]; + } + +} \ No newline at end of file diff --git a/src/main/java/com/ziyu/stack/MyStack.java b/src/main/java/com/ziyu/stack/MyStack.java new file mode 100644 index 0000000..98dc465 --- /dev/null +++ b/src/main/java/com/ziyu/stack/MyStack.java @@ -0,0 +1,116 @@ +package com.ziyu.stack; + + +import java.util.Scanner; + +/** + * 利用数组模拟一个栈 + */ +public class MyStack { + + public static void main(String[] args) { + + ArrayStack stack = new ArrayStack(4); + //测试一下ArrayStack 是否正确 + //先创建一个ArrayStack对象->表示栈 + 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": + stack.list(); + break; + case "push": + System.out.println("请输入一个数"); + int value = scanner.nextInt(); + stack.push(value); + break; + case "pop": + try { + int res = stack.pop(); + System.out.printf("出栈的数据是 %d\n", res); + } catch (Exception e) { + // TODO: handle exception + System.out.println(e.getMessage()); + } + break; + case "exit": + scanner.close(); + loop = false; + break; + default: + 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()) { + return; + } + top++; + stack[top] = value; + } + + //出栈 + public int pop() { + if (isEmpty()) { + System.out.println("栈为空"); + throw new RuntimeException("栈空了"); + } + int value = stack[top]; + top--; + return value; + } + + //遍历栈 必须从栈顶显示数据 + public void list() { + if (isEmpty()) { + System.out.println("栈为空"); + } + + for (int i = top; i >= 0; i--) { + System.out.printf("stack[%d]=%d\n", i, stack[i]); + } + } + +} diff --git a/src/main/java/com/ziyu/stack/PolandNotation.java b/src/main/java/com/ziyu/stack/PolandNotation.java new file mode 100644 index 0000000..b198d9e --- /dev/null +++ b/src/main/java/com/ziyu/stack/PolandNotation.java @@ -0,0 +1,192 @@ +package com.ziyu.stack; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 逆波兰表达式 + */ +public class PolandNotation { + public static void main(String[] args) { + + //(30+4)*5-6 + String suffixExpresstion = "30 4 + 5 * 6 - "; //后缀表达式 + + //1.扫描放到ArrayList里面 + List list = getListString(suffixExpresstion); + + + //2.将ArrayList传入方法里面,然后放入栈完成 + System.out.println(calc(list)); + + + /** + * 中缀表达式转换后缀表达式 + * eg: + * 1+((2+3)*4) -5 --> 后缀表达式 + * 思路: + * 1.初始化两个栈,运算符栈s1,和中间结果(数字)的栈s2 + * 2.从左至有开始扫描中缀表达式 + * 3.遇到操作数的时候将其压入s2 + * 4.碰到运算符,比较s1的栈顶的运算符额优先级; + * 4.1 如果s1为空,或者栈顶运算符为'(',直接入栈 + * + * 5.遇到括号 + * 5.1遇到左括号,直接入栈s1。。。。 + * + * 1+((2+3)*4)-5 --> 1 2 3 + 4 * + 5 1 + * 由于对str直接处理不方便,我们将其放到List里面 + */ + + String middleExpresstion = "1+((2+3)*4)-5"; + List list2 = middle2List(middleExpresstion); //中缀表达式 转成每一个字符处理 + System.out.println(list2); + + //3,中缀表达式转换后缀 + List list3 = infix2shuffixExpresstion(list2); + System.out.println(list3); + System.out.println(middleExpresstion + "=" + calc(list3)); + + } + + public static List infix2shuffixExpresstion(List infixList) { + + //定义两个栈 + Stack s1 = new Stack<>(); //符号栈 + + //因为s2 在整个栈中没有pop操作,所以,就将s2用list替代 +// Stack s2 = new Stack<>(); + + ArrayList s2 = new ArrayList<>(); + + //取出来每一个item + for (String item : infixList) { + 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栈顶的元素的优先级,这里需要一个比较优先级的方法 + while (s1.size() != 0 && Operation.getOperation(s1.peek()) >= Operation.getOperation(item)) { + s2.add(s1.pop()); + } + //还需要将Item压入栈中 + s1.push(item); + } + + } + + //将s1的元素加入到s2中即可 + while (s1.size() != 0) { + + s2.add(s1.pop()); + } + + return s2; //逆序输出的就是逆波兰表达式 + } + + public static List middle2List(String middle) { + ArrayList ls = new ArrayList<>(); + + int i = 0; + String str = "";//对多位数进行拼接使用 + char c; //每遍历一个字符都放入c中 + do { + if ((c = middle.charAt(i)) < 48 || (c = middle.charAt(i)) > 57) { //c是一个非数字 + ls.add("" + c); + i++; + } else { //考虑是多位数 + str = ""; + while (i < middle.length() && (c = middle.charAt(i)) >= 48 && (c = middle.charAt(i)) <= 57) { + str += c; + i++; + } + ls.add(str); + } + } while (i < middle.length()); + return ls; + } + + public static List getListString(String expression) { + String[] split = expression.split(" "); + + ArrayList list = new ArrayList(); + for (String s : split) { + list.add(s); + } + return list; + } + + public static int calc(List list) { + Stack stack = new Stack(); + + for (String item : list) { + if (item.matches("\\d+")) { + stack.push(item); + } else { + int num2 = Integer.parseInt(stack.pop()); + int num1 = Integer.parseInt(stack.pop()); + int res = 0; + if (item.equals("+")) { + res = num1 + num2; + } else if (item.equals("-")) { + res = num1 - num2; + + } else if (item.equals("*")) { + res = num1 * num2; + } else if (item.equals("/")) { + res = num1 / num2; + } else { + throw new RuntimeException("运算符有误!"); + } + stack.push("" + res); + } + + } + //最终留在栈里面的就是结果 + return Integer.parseInt(stack.pop()); + } +} + +//返回运算符号的优先级 Operation返回对应符号的优先级! +class Operation { + + private static int ADD = 1;//+ + private static int SUB = 1;//- + private static int MUL = 2;//* + private static int DIV = 2;// chu + + public static int getOperation(String operation) { + int result = 0; + switch (operation) { + case "+": + result = ADD; + break; + case "-": + result = SUB; + break; + case "*": + result = MUL; + break; + case "/": + result = DIV; + break; + default: + System.out.println("不存在该运算符!"); + break; + } + + return result; + } + +} \ No newline at end of file