稀疏数组
二维数组转稀疏数组的思路
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;
}
}
}
}
八皇后问题
八皇后问题算法思路分析
- 第一个皇后先放第一行第一列
- 第二个皇后放在第二行第一列、然后判断是否0K, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
- 继续第三个皇后,还是第一-列、第二列…直到第8个皇后也能放在一一个不冲突的位置,算是找到了一个正确解
- 当得到一-个正确解时,在栈回退到上一一个栈时,就会开始回溯,即将第
一个皇后,放到第一列的所有正确解,全部得到。 - 然后回头继续第一个皇后放第二列,后面继续循环执行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));
}
}