普通表达式的计算
public class ArrayStackDemo {
public static void main(String[] args) {
String expr = "3-2-1";
// String expr = "96+54*2-34-64+87+65-34*2-57";
ArrStack numStack = new ArrStack(20);
ArrStack opeStack = new ArrStack(20);
//扫描表达式
int index = 0;
//定义一个str记录扫描到的多位数
StringBuffer str = new StringBuffer();
char ch = ' '; // 记录扫描到的字符
while(index < expr.length()) {
str.replace(0, str.length(), "");
ch = expr.substring(index, index + 1).charAt(0);
// 如果ch是一个数,那么要判断下一位是数还是符号
if(!numStack.isOperator(ch)) {
while(!numStack.isOperator(ch) && index < expr.length()) {
index ++;
str.append(ch);
if(index < expr.length()) ch = expr.substring(index, index + 1).charAt(0);
}
numStack.push(Integer.parseInt(str.toString()));
}
else { // 是一个符号
//当前扫描到的符号的优先级大于原来的优先级或者符号栈为空,那么直接入栈
if(opeStack.isEmpty() || opeStack.priority(opeStack.peek()) < opeStack.priority(ch))
opeStack.push(ch);
else { // 当前扫描到的符号优先级小于等于符号栈顶的优先级
int num2 = numStack.pop();
int num1 = numStack.pop();
numStack.push(numStack.calculate(num1, num2, (char)opeStack.pop()));
//如果符号栈顶端的符号是 '-' 那么还要先计算其中的减号
if(!opeStack.isEmpty() && opeStack.peek() == '-') {
//先从数栈中pop出两个数
num2 = numStack.pop();
num1 = numStack.pop();
numStack.push(numStack.calculate(num1, num2, (char)opeStack.pop()));
}
opeStack.push(ch);
}
index ++;
}
}
//扫描结束
while(!opeStack.isEmpty()){
int num2 = numStack.pop();
int num1 = numStack.pop();
numStack.push(numStack.calculate(num1, num2, (char)opeStack.pop()));
}
System.out.printf("表达式%s = %d\n", expr, numStack.pop());
}
}
class ArrStack {
private int[] arr;
private int maxSize;
private int rear;
public ArrStack(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
rear = -1;
}
public boolean isEmpty() {
return rear == -1;
}
public boolean isFull() {
return rear == maxSize - 1;
}
public void push(int ele) {
if(isFull()) {
System.out.println("栈已满,无法加入新元素~~");
return;
}
arr[++ rear] = ele;
}
public int pop() {
if(isEmpty())
throw new RuntimeException("栈为空,无法pop出元素~~");
return arr[rear --];
}
public int peek() {
if(isEmpty())
throw new RuntimeException("栈为空,无法peek~~");
return arr[rear];
}
public void showData() {
if(isEmpty()) {
System.out.println("栈为空,没有元素可show~~");
return;
}
for (int i = 0; i <= rear; i++) {
System.out.printf("arr[%d] = %d\t", i, arr[i]);
}
System.out.println();
}
public boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
public int priority(int ope) {
return (ope == '*' || ope == '/')? 1: 0;
}
public int calculate(int num1, int num2, char ope) {
switch (ope) {
case'+':
return num1 + num2;
case'-':
return num1 - num2;
case'*':
return num1 * num2;
case'/':
return num1 / num2;
default:
throw new RuntimeException("操作符错误~~请检查");
}
}
}
普通中缀表达式转逆波兰表达式后再计算
public class PolandNotation {
/**
* 1. 初始化两个栈,运算符栈s1和中间栈s2
* 2. 从左往右扫描中缀表达式
* 3. 遇到操作数时,直接压s2
* 4. 遇到运算符时,比较其与s1栈顶运算符的优先级
* 4.1 如果s1为空,或栈顶运算符为左括号"(",则直接将此运算符入栈
* 4.2 否则,若优先级比栈顶运算符的高,也将运算符压入s1
* 4.3 否则,将s1栈顶的运算符弹出并压入s2中,再次转到4.1与s1中新的栈顶运算符相比较
* 5. 遇到括号时
* 5.1 如果是左括号"(",则直接压入s1
* 5.2 如果是右括号")",则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号位置,此时将这一对括号丢弃
* 6. 重复步骤2-5,直到表达式的最右边
* 7. 将s1中剩于的运算符依次弹出并压入s2
* 8. 终止
* 将listExpression转逆波兰表达式,转好的字符串应该带空格隔开
*/
public static void main(String[] args) {
String expr = "(3*6-9)*2*(4-3)+9-8";
//转成逆波兰表达式字符串,空格隔开
String suffixStr = exprToSuffix(expr);
//计算逆波兰表达式
int res = calculateExpr(suffixStr);
System.out.printf("表达式%s = %d\n", expr, res);
}
public static int calculateExpr(String expr) {
//得到的expr的形式如:"3 4 1 - 8 * + 2 + 8 - 8 4 / + 10 10 * - "
ArrStack arrStack = new ArrStack(20);
int num1, num2;
for(String item: expr.split(" ")) {
if(item.matches("\\d+")) { // 匹配的是多位数字
arrStack.push(Integer.parseInt(item));
}
else { // 匹配的是操作符
num2 = arrStack.pop();
num1 = arrStack.pop();
arrStack.push(arrStack.calculate(num1, num2, item.charAt(0)));
}
}
return arrStack.pop();
}
public static String exprToSuffix(String expr) {
//先写一个将此中缀表达式转逆波兰表达式所需要的符号栈
String res = ""; // 用于接收最终需要的逆波兰表达式的字符串,用空格隔开
int index = 0;
//扫描此表达式
char ch = ' ';
ArrStack stack = new ArrStack(30);
while(index < expr.length()) {
if(isOpe(ch = (expr.substring(index, index + 1).charAt(0)))) { // 扫描到运算符
while(true) {
if(stack.isEmpty() || stack.peek() == '(' || stack.priority(stack.peek()) < stack.priority(ch)) {
stack.push(ch);
break;
}
res = res + (char)stack.pop() + " ";
}
index ++;
}
else if(isNum(ch)) { // 当前扫描到的是数字,那么还需要继续扫描直到不是数字
while(index < expr.length() && isNum(ch)) {
res = res + ch;
index ++;
if(index < expr.length()) ch = expr.substring(index, index + 1).charAt(0);
}
res = res + " ";
}
else { // 扫描到的是括号
if(ch == '(') stack.push(ch);
else { // 遇到了右括号
while(stack.peek() != '(') {
res = res + (char)stack.pop() + " ";
}
stack.pop(); // 弹出没用的左括号
}
index ++;
}
}
while(!stack.isEmpty()) {
res = res + (char)stack.pop() + " ";
}
return res;
}
public static boolean isOpe(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
public static boolean isNum(char ch) {
return ch >= 48 && ch <= 57;
}
}
class ArrStack {
private int[] arr;
private int maxSize;
private int rear;
public ArrStack(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
rear = -1;
}
public boolean isEmpty() {
return rear == -1;
}
public boolean isFull() {
return rear == maxSize - 1;
}
public void push(int ele) {
if(isFull()) {
System.out.println("栈已满,无法加入新元素~~");
return;
}
arr[++ rear] = ele;
}
public int pop() {
if(isEmpty())
throw new RuntimeException("栈为空,无法pop出元素~~");
return arr[rear --];
}
public int peek() {
if(isEmpty())
throw new RuntimeException("栈为空,无法peek~~");
return arr[rear];
}
public void showData() {
if(isEmpty()) {
System.out.println("栈为空,没有元素可show~~");
return;
}
for (int i = 0; i <= rear; i++) {
System.out.printf("arr[%d] = %d\t", i, arr[i]);
}
System.out.println();
}
public int priority(int ope) {
return (ope == '*' || ope == '/')? 1: 0;
}
public int calculate(int num1, int num2, char ope) {
switch (ope) {
case'+':
return num1 + num2;
case'-':
return num1 - num2;
case'*':
return num1 * num2;
case'/':
return num1 / num2;
default:
throw new RuntimeException("操作符错误~~请检查");
}
}
}
走迷宫的问题
public class MazeSolution {
public static void main(String[] args) {
int[][] map = new int[8][7]; // 大小为8*7的迷宫
initialMap(map);
printArray(map);
setWay(map, 1, 1);
printArray(map);
}
//初始化地图
public static void initialMap(int[][] map) {
/**
* 用0表示可以走的路
* 用1表示墙体
* 用2表示已经走过的路
* 用3表示这条路已经走多了而且走不通
*/
//上下全部置为1
for(int i = 0; i < map[0].length; i++){
map[0][i] = 1;
map[map.length - 1][i] = 1;
}
//左右全部置1
for(int i = 1; i < map.length - 1; i++){
map[i][0] = 1;
map[i][map[0].length - 1] = 1;
}
//设置挡板
map[3][1] = 1;
map[3][2] = 1;
map[2][3] = 1;
map[2][2] = 1;
map[4][5] = 1;
map[5][3] = 1;
map[5][4] = 1;
}
//打印地图
public static void printArray(int [][] arr) {
System.out.println("地图的情况~~");
for(int[] row:arr){
for(int ele:row){
System.out.print(ele + " ");
}
System.out.println();
}
}
/**
* @param map 表示地图
* @param i j 从地图哪个位置开始出发找路
* @return 找到通路就返回true,否则返回false
* 走到地图的map[-1][-1]时代表到达终点
* 确定一个策略方法,下>右>上>左,如果该点走不通则回溯
*/
public static boolean setWay(int[][] map, int i, int j) {
if(map[map.length - 2][map[0].length - 2] == 2) return true;
//当前这个点没有被走过
if(map[i][j] == 0) {
map[i][j] = 2; //标记已经走过了
if(setWay(map, i + 1, j) || setWay(map, i, j + 1) || setWay(map, i - 1, j) || setWay(map, i, j - 1)) {
return true;
}
map[i][j] = 3;
}
return false;
}
//完整版
/*
public static boolean setWay(int [][]map, int i, int j){
if(map[map.length - 2][map[0].length - 2] == 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;
}
}
}*/
}
八皇后问题简单递归实现
public class Queen8 {
static int max = 8;
static int count = 0; // 表示一共有多少种放置的方法
static int[] queenArray = new int[max];
public static void main(String[] args) {
//先创建一个8*8的格子用于记录皇后摆放
/**
* 用一个一维数组即可解决该问题
* [0, 4, 7, 5, 2, 6, 1, 3] 其中第1个皇后放在第1行第1列
* 第2个皇后放在第2行第5列...第8个皇后放在第8行第4列
*/
playQueen(0);
System.out.println(count);
}
//打印出皇后摆放的位置
public static void printQueenLocation(){
for(int elem:queenArray){//都要设置成static才能访问queenArray
System.out.print(elem + " ");
}
System.out.println();
}
//放置第n个皇后的位置
public static void playQueen(int n) {
if(n == max) {
count ++;
printQueenLocation();
return;
} // 表示前0-7个已经放完了,想放第8个时游戏结束
for (int i = 0; i < max; i++) {
queenArray[n] = i; // 先把这个皇后放在这个位置再判断是否冲突,如果不冲突,那么放下一个
if(judgeConflict(n)) {
playQueen(n + 1);
}
}
}
//判断这个皇后的位置是否与前面的冲突
public static boolean judgeConflict(int i) {
for(int j = 0; j < i; j++) {
if(queenArray[i] == queenArray[j] || (i - j) == Math.abs(queenArray[i] - queenArray[j])) return false;
}
return true;
}
}
冒泡排序算法
//冒泡排序
public static void popSort(int[] arr) {
int n = arr.length;
//n个数要经过n-1轮排序
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if(arr[j] > arr[j + 1]) swap(arr, j, j + 1);
}
}
}
选择排序算法
public static void selectSort(int[] arr) {
int n = arr.length;
int max, index;
for (int i = n - 1; i > 0; i--) { // 先与最后一个数进行交换,即找最大的数
max = arr[0];
index = 0;
for (int j = 1; j < i + 1; j++) {
if(max < arr[j]) {
max = arr[j];
index = j;
}
}
swap(arr, i, index);
}
}
插入排序算法
public static void insertSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) { // 假设的是第0个元素为有序
int ele = arr[i], index = i; // 将要插入的这个元素保存起来
for (int j = i - 1; j >= 0; j--) {
if(arr[j] > ele) {
arr[j + 1] = arr[j];
index = j;
}
else break;
}
arr[index] = ele;
}
}
希尔排序
public static void xerSort(int[] arr) {
int n = arr.length;
for (int foot = n / 2; foot > 0; foot /= 2) {
for (int j = foot; j < n; j ++) {
int index = j;
int ele = arr[j];
for (int i = j - foot; i >= 0; i -= foot) {
if(arr[i] > ele) {
index = i;
arr[i + foot] = arr[i];
}
else break;
}
arr[index] = ele;
}
}
}
快速排序算法
public static void quickSort(int[] arr, int left, int right) {
if(left >= right) return;
//取最左边的数为基准数
int baseVal = arr[left];
int i = left, j = right;
while(i < j) {
//右边的j先动
while(i < j && arr[j] >= baseVal) {
j --;
}
while(i < j && arr[i] <= baseVal) {
i ++;
}
if(i == j) swap(arr, left, i);
else swap(arr, i, j);
}
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
归并排序算法
//归并排序
public static void mergeSort(int[] arr) {
int[] temp = new int[arr.length];
divide(arr, 0, arr.length - 1, temp);
}
//分
public static void divide(int[] arr, int left, int right, int[] temp) {
if(left < right) {
int mid = (left + right) / 2;
divide(arr, left, mid, temp);
divide(arr, mid + 1, right, temp);
merge(arr, left, mid + 1, right, temp);
}
}
//治
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int l = left, m = mid;
int tIndex = 0;
while(l < mid && m <= right) {
temp[tIndex ++] = (arr[l] < arr[m])?arr[l ++]:arr[m ++];
}
while(l < mid) {
temp[tIndex ++] = arr[l ++];
}
while(m <= right) {
temp[tIndex ++] = arr[m ++];
}
tIndex = 0;
//将temp数组拷贝回原始数组
int index = left;
while(index <= right) {
arr[index ++] = temp[tIndex ++];
}
}
还剩一种基数排序算法就明天再复习啦~~