/**
* 定义栈接口
*/
public interface Stack {
/**
* 判断栈满
*
* @return
*/
boolean isFull();
/**
* 判断栈空
*
* @return
*/
boolean isEmpty();
/**
* 入栈-push
*/
void push(int value);
/**
* 出栈-pop
*/
int pop();
/**
* 查看栈顶的元素
*/
int peek();
/**
* 遍历栈
*/
void show();
}
/**
* 数组实现栈
*/
class ArrayStack implements Stack {
/**
* 栈的大小
*/
private int maxSize;
/**
* 数组模拟栈
*/
private int[] stack;
/**
* 栈顶,初始化为-1
*/
private int top = -1;
public ArrayStack(int maxSize) {
this.maxSize = maxSize <= 0 ? 0 : maxSize;
stack = new int[this.maxSize];
}
@Override
public boolean isFull() {
return top == maxSize - 1;
}
@Override
public boolean isEmpty() {
return top == -1;
}
@Override
public void push(int value) {
if (isFull()) {
throw new RuntimeException("栈满了~~");
}
top++;
stack[top] = value;
}
@Override
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据~~");
}
int value = stack[top];
top--;
return value;
}
@Override
public int peek() {
return stack[top];
}
@Override
public void show() {
if (isEmpty()) {
System.out.println("栈空,没有数据~~");
return;
}
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d]=%d\n", i, stack[i]);
}
}
}
public class StackApp {
public static void play(Stack stack, String subject) {
System.out.println(subject);
// 菜单
System.out.println("show:显示栈");
System.out.println("exit:退出程序");
System.out.println("push[空格][number]:添加数据到栈(入栈)");
System.out.println("pop:从栈获取数据(出栈)");
System.out.println("peek:查看栈顶的数据");
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
// 接收一个字符
String command = scanner.nextLine().trim();
String[] commands = command.split(" ");
switch (commands[0]) {
case "show":
stack.show();
break;
case "exit":
scanner.close();
loop = false;
break;
case "push":
try {
int value = Integer.parseInt(commands[1]);
stack.push(value);
System.out.printf("%d入栈成功!\n", value);
} catch (Exception e) {
System.out.println(e.getMessage() + " 入栈失败!");
}
break;
case "pop":
try {
int value = stack.pop();
System.out.printf("出栈的数据是%d\n", value);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case "peek":
try {
int value = stack.peek();
System.out.printf("栈顶的数据是%d\n", value);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default:
break;
}
}
}
}
public class ArrayStackDemo {
public static void main(String[] args) {
StackApp.play(new ArrayStack(4), "数组实现栈功能演示~~");
}
}
数组实现栈功能演示~~
show:显示栈
exit:退出程序
push[空格][number]:添加数据到栈(入栈)
pop:从栈获取数据(出栈)
peek:查看栈顶的数据
show
栈空,没有数据~~
push 1
1入栈成功!
push 2
2入栈成功!
push 3
3入栈成功!
push 5
5入栈成功!
push 8
栈满了~~ 入栈失败!
peek
栈顶的数据是5
pop
出栈的数据是5
pop
出栈的数据是3
pop
出栈的数据是2
pop
出栈的数据是1
pop
栈空,没有数据~~
peek
-1
exit
/**
* 链表实现栈
*/
class LinkedListStack implements Stack {
/**
* 定义一个双向链表
*/
static class LinkedNode {
private Integer value;
private LinkedNode next;
private LinkedNode pre;
public LinkedNode(Integer value) {
this.value = value;
}
}
/**
* 栈的大小
*/
private int maxSize;
/**
* 记录链表有效数据长度
*/
private int counter = 0;
/**
* 链表模拟栈
*/
private LinkedNode head;
/**
* 栈顶
*/
private LinkedNode top;
public LinkedListStack(int maxSize) {
this.maxSize = maxSize;
// 初始化头结点和栈顶
head = new LinkedNode(null);
top = head.next;
}
@Override
public boolean isFull() {
return counter == maxSize;
}
@Override
public boolean isEmpty() {
return head.next == null;
}
@Override
public void push(int value) {
if (isFull()) {
throw new RuntimeException("栈满了~~");
}
LinkedNode node = new LinkedNode(value);
node.pre = top;
if (top == null) {
head.next = node;
node.pre = head;
} else {
top.next = node;
}
top = node;
counter++;
}
@Override
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据~~");
}
int value = top.value;
LinkedNode pre = top.pre;
top.pre = null;
top = pre;
top.next = null;
counter--;
return value;
}
@Override
public int peek() {
return top.value;
}
@Override
public void show() {
LinkedNode cursor = head.next;
while (cursor != null) {
System.out.printf("%d -> ", cursor.value);
cursor = cursor.next;
}
System.out.println("null");
}
}
public class LinkedListStackDemo {
public static void main(String[] args) {
StackApp.play(new LinkedListStack(4), "链表实现栈功能演示~~");
}
}
链表实现栈功能演示~~
show:显示栈
exit:退出程序
push[空格][number]:添加数据到栈(入栈)
pop:从栈获取数据(出栈)
peek:查看栈顶的数据
show
null
push 1
1入栈成功!
push 2
2入栈成功!
push 3
3入栈成功!
show
1 -> 2 -> 3 -> null
push 4
4入栈成功!
push 5
栈满了~~ 入栈失败!
pop
出栈的数据是4
pop
出栈的数据是3
peek
栈顶的数据是2
pop
出栈的数据是2
pop
出栈的数据是1
pop
栈空,没有数据~~
show
null
exit
* 从右至左扫描,将6、5、4、3压入堆栈
* 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素),计算出3+4的值,得7,再将7入栈
* 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
* 最后是-运算符,计算出35-6的值,即29,由此得出最终结果
* 从左至右扫描,将3和4压入堆栈
* 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈
* 将5入栈
* 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈
* 将6入栈
* 最后是-运算符,计算出35-6的值,即29,由此得出最终结果
后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将 中缀表达式转成后缀表达式。具体步骤如下:
1. 若栈为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈
2. 否则,若优先级比栈顶运算符的高,也将运算符压入栈中
3. 否则,栈顶的运算符弹出,并加入到输出队列中,再次转到步骤(③-1)与stack中新的栈顶运算符相比较
4. 若是左括号"(",则直接压入栈中;
5. 若是右括号")",则依次弹出栈顶的运算符,并加入到输出队列中,直至遇到左括号,此时将这一对括号丢弃
序号 | 元素 | 栈stack | 输出队列queue(头->尾) | 说明 |
---|---|---|---|---|
1 | a | 空 | a | 数字a,直接入队列 |
2 | + | + | a | 栈空,运算符+直接入栈 |
3 | b | + | a b | 数字b,直接入队列 |
4 | * | + * | a b | 运算符*优先级高于+,直接入栈 |
5 | c | + * | a b c | 数字c,直接入队列 |
6 | + | + | a b c * + | +优先级不大于 *、+,则*、+依次入队,再将+入栈 |
7 | ( | + ( | a b c * + | 左括号,直接入栈 |
8 | d | + ( | a b c * + d | 数字d,直接入队列 |
9 | * | + ( * | a b c * + d | 栈顶为左括号,运算符直接入栈 |
10 | e | + ( * | a b c * + d e | 数字e,直接入队列 |
11 | + | + ( + | a b c * + d e * | 同第6步 |
12 | f | + ( + | a b c * + d e * f | 数字f,直接入队列 |
13 | ) | + | a b c * + d e * f + | 栈顶为右括号,弹出运算符直至遇到"(" |
14 | * | + * | a b c * + d e * f + | 同第4步 |
15 | g | + * | a b c * + d e * f + g | 数字g,直接入队列 |
16 | 空 | a b c * + d e * f + g * + | 栈中剩余的操作数依次出栈,并入队列 |
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;
public class Calculator {
private static final String ADD = "+";
private static final String SUB = "-";
private static final String MUL = "*";
private static final String DIV = "/";
private static final String LEFT = "(";
private static final String RIGHT = ")";
private static final int PRIORITY_ZERO = 0;
private static final int PRIORITY_LOW = 1;
private static final int PRIORITY_HIGH = 2;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个中缀表达式:");
String infixExp = (sc.nextLine()).trim();
String suffixExp = parseSuffixExp(infixExp);
System.out.printf("对应的后缀表达式:%s\n", suffixExp);
System.out.printf("后缀表达式计算结果:%s\n", calculate(suffixExp));
}
/**
* 解析中缀表达式为后缀表达式
*/
private static String parseSuffixExp(String infixExp) {
if (infixExp == null || "".equals(infixExp)) {
return infixExp;
}
// 定义一个栈用于存放运算符
Stack<String> stack = new Stack<>();
// 定义一个StringBuffer用于拼接后缀表达式
StringBuffer sb = new StringBuffer();
String[] elements = infixExp.split(" ");
for (String ele : elements) {
parseElement(ele, stack, sb);
}
// 栈中剩余的操作数依次出栈,并进行结果拼接
while (!stack.isEmpty()) {
sb.append(stack.pop()).append(" ");
}
return sb.toString();
}
private static void parseElement(String ele, Stack<String> stack, StringBuffer sb) {
if (isNumber(ele)) {
// 如果是数字,直接sb拼接(多位数也一样)
sb.append(ele).append(" ");
} else if (isSymbol(ele)) {
if (stack.isEmpty()) {
// 如果栈空,则运算符直接入栈
stack.push(ele);
} else {
// 否则,比较栈顶的元素运算符的优先级
while (!stack.isEmpty() && getPriority(stack.peek()) >= getPriority(ele)) {
sb.append(stack.pop()).append(" ");
}
// 最后还得将当前的运算符入栈
stack.push(ele);
}
} else if (LEFT.equals(ele)) {
// 如果是左括号,则直接入栈
stack.push(ele);
} else if (RIGHT.equals(ele)) {
// 如果是右括号,则依次弹出栈顶的运算符,并加入到输出队列中(进行sb拼接),直至遇到"("
while (!stack.peek().equals(LEFT)) {
sb.append(stack.pop()).append(" ");
}
// 最后消除左括号,将"("弹出
stack.pop();
} else {
throw new RuntimeException("未知符号:" + ele);
}
}
/**
* 根据后缀表达式计算
*/
private static int calculate(String suffixExp) {
if (suffixExp == null || "".equals(suffixExp)) {
throw new RuntimeException("运算表达式空~~");
}
// 创建一个栈,用于后缀表达式的计算
Stack<String> stack = new Stack<>();
// 按空格拆分表达式
String[] elements = suffixExp.split(" ");
// 遍历
for (String ele : elements) {
// 如果是数字,则直接入栈
if (isNumber(ele)) {
stack.push(ele);
} else {
// 否则,弹出两个数,进行运算后,结果再入栈
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
stack.push(String.valueOf(doCalculate(num1, num2, ele)));
}
}
// 最后留在 stack 中的数据就是运算结果
return Integer.parseInt(stack.pop());
}
private static int doCalculate(int num1, int num2, String symbol) {
switch (symbol) {
case ADD:
return num1 + num2;
case SUB:
return num1 - num2;
case MUL:
return num1 * num2;
case DIV:
return num1 / num2;
default:
throw new RuntimeException("运算符有误");
}
}
/**
* 判断是否为整数
*/
private static boolean isNumber(String ele) {
return ele.matches("\\d+");
}
/**
* 判断是否为(+-*\)运算符
*/
private static boolean isSymbol(String ele) {
return Arrays.asList(ADD, SUB, MUL, DIV).contains(ele);
}
private static int getPriority(String s) {
if (ADD.equals(s) || SUB.equals(s)) {
return PRIORITY_LOW;
}
if (MUL.equals(s) || DIV.equals(s)) {
return PRIORITY_HIGH;
}
return PRIORITY_ZERO;
}
}
请输入一个中缀表达式:4 * 5 - 8 + 60 + 8 / 2
对应的后缀表达式:4 5 * 8 - 60 + 8 2 / +
后缀表达式计算结果:76
public abstract class Calculator {
protected static final String ADD = "+";
protected static final String SUB = "-";
protected static final String MUL = "*";
protected static final String DIV = "/";
private static final String LEFT = "(";
private static final String RIGHT = ")";
private static final int PRIORITY_ZERO = 0;
private static final int PRIORITY_LOW = 1;
private static final int PRIORITY_HIGH = 2;
public void play() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个中缀表达式:");
String infixExp = (sc.nextLine()).trim();
String suffixExp = parseSuffixExp(infixExp);
System.out.printf("对应的后缀表达式:%s\n", suffixExp);
System.out.printf("后缀表达式计算结果:%s\n", calculate(suffixExp));
}
/**
* 解析中缀表达式为后缀表达式
*/
private String parseSuffixExp(String infixExp) {
if (infixExp == null || "".equals(infixExp)) {
return infixExp;
}
// 定义一个栈用于存放运算符
Stack<String> stack = new Stack<>();
// 定义一个StringBuffer用于拼接后缀表达式
StringBuffer sb = new StringBuffer();
String[] elements = infixExp.split(" ");
for (String ele : elements) {
parseElement(ele, stack, sb);
}
// 栈中剩余的操作数依次出栈,并进行结果拼接
while (!stack.isEmpty()) {
sb.append(stack.pop()).append(" ");
}
return sb.toString();
}
private void parseElement(String ele, Stack<String> stack, StringBuffer sb) {
if (isNumber(ele)) {
// 如果是数字,直接sb拼接(多位数也一样)
sb.append(ele).append(" ");
} else if (isSymbol(ele)) {
if (stack.isEmpty()) {
// 如果栈空,则运算符直接入栈
stack.push(ele);
} else {
// 否则,比较栈顶的元素运算符的优先级
while (!stack.isEmpty() && getPriority(stack.peek()) >= getPriority(ele)) {
sb.append(stack.pop()).append(" ");
}
// 最后还得将当前的运算符入栈
stack.push(ele);
}
} else if (LEFT.equals(ele)) {
// 如果是左括号,则直接入栈
stack.push(ele);
} else if (RIGHT.equals(ele)) {
// 如果是右括号,则依次弹出栈顶的运算符,并加入到输出队列中(进行sb拼接),直至遇到"("
while (!stack.peek().equals(LEFT)) {
sb.append(stack.pop()).append(" ");
}
// 最后消除左括号,将"("弹出
stack.pop();
} else {
throw new RuntimeException("未知符号:" + ele);
}
}
/**
* 根据后缀表达式计算
*/
private String calculate(String suffixExp) {
if (suffixExp == null || "".equals(suffixExp)) {
throw new RuntimeException("运算表达式空~~");
}
// 创建一个栈,用于后缀表达式的计算
Stack<String> stack = new Stack<>();
// 按空格拆分表达式
String[] elements = suffixExp.split(" ");
// 遍历
for (String ele : elements) {
// 如果是数字,则直接入栈
if (isNumber(ele)) {
stack.push(ele);
} else {
// 否则,弹出两个数,进行运算后,结果再入栈
String pop2 = stack.pop();
String pop1 = stack.pop();
stack.push(doCalculate(pop1, pop2, ele));
}
}
// 最后留在 stack 中的数据就是运算结果
return stack.pop();
}
/**
* 具体计算
*/
public abstract String doCalculate(String ele1, String ele2, String symbol);
/**
* 判断是否为整数
*/
protected boolean isNumber(String ele) {
return ele.matches("^[-\\+]?[.\\d]+$");
}
/**
* 判断是否为(+-*\)运算符
*/
protected boolean isSymbol(String ele) {
return Arrays.asList(ADD, SUB, MUL, DIV).contains(ele);
}
/**
* 获取运算符优先级
*/
protected int getPriority(String symbol) {
if (ADD.equals(symbol) || SUB.equals(symbol)) {
return PRIORITY_LOW;
}
if (MUL.equals(symbol) || DIV.equals(symbol)) {
return PRIORITY_HIGH;
}
return PRIORITY_ZERO;
}
}
public class IntegerCalculatorDemo {
public static void main(String[] args) {
new IntegerCalculator().play();
}
}
class IntegerCalculator extends Calculator {
@Override
public String doCalculate(String ele1, String ele2, String symbol) {
Integer num1 = Integer.parseInt(ele1);
Integer num2 = Integer.parseInt(ele2);
switch (symbol) {
case ADD:
return String.valueOf(num1 + num2);
case SUB:
return String.valueOf(num1 - num2);
case MUL:
return String.valueOf(num1 * num2);
case DIV:
return String.valueOf(num1 / num2);
default:
throw new RuntimeException("运算符有误");
}
}
}
public class DoubleCalculatorDemo {
public static void main(String[] args) {
new DoubleCalculator().play();
}
}
class DoubleCalculator extends Calculator {
@Override
public String doCalculate(String ele1, String ele2, String symbol) {
Double num1 = Double.parseDouble(ele1);
Double num2 = Double.parseDouble(ele2);
switch (symbol) {
case ADD:
return String.valueOf(num1 + num2);
case SUB:
return String.valueOf(num1 - num2);
case MUL:
return String.valueOf(num1 * num2);
case DIV:
return String.valueOf(num1 / num2);
default:
throw new RuntimeException("运算符有误");
}
}
}
public class RecursionTest {
public static void main(String[] args) {
System.out.println("打印问题");
test(4);
}
private static void test(int n) {
if (n > 2) {
test(n - 1);
}
System.out.println("n = " + n);
}
}
public class RecursionTest {
public static void main(String[] args) {
System.out.printf("阶乘计算:%d\n", factorial(4));
}
private static int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
}
public class MazeDemo {
/**
* 迷宫类
* 约定:map[i][j] = 0:该点没有走过, 1:墙, 2:通路可以走, 3:已经走过但走不通
*/
private static class Maze {
private int[][] map;
private static final int WALL = 1;
private static final int ROUTE = 2;
private static final int NO_ROUTE = 3;
/**
* 起点x y坐标
*/
private int startX;
private int startY;
/**
* 终点x y坐标
*/
private int endX;
private int endY;
public Maze(int[][] map, int startX, int startY, int endX, int endY) {
this.map = map;
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
private void printMap() {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
System.out.printf("%d ", map[i][j]);
}
System.out.println();
}
}
private void findWay() {
boolean result = findWayDRUL(startX, startY);
if (result) {
System.out.println("找到一条出迷宫的路~~");
} else {
System.out.println("没有找到出迷宫的路");
}
}
/**
* 需要确定一个策略(方法) 下(D)->右(R)->上(U)->左(L) , 如果该点走不通,再回溯
* @param x
* @param y
* @return
*/
private boolean findWayDRUL(int x, int y) {
if (map[endX][endY] == ROUTE) {
return true;
} else {
if (map[x][y] == 0) {
// 当前这个点还没有走过
// 假定该点是可以走通的
map[x][y] = ROUTE;
if (findWayDRUL(x + 1, y)) { // 向下走
return true;
} else if (findWayDRUL(x, y +1)) { // 向右走
return true;
} else if (findWayDRUL(x - 1, y)) { // 向上走
return true;
} else if (findWayDRUL(x, y - 1)) { // 向左走
return true;
} else {
// 说明该点走不通,是死路
map[x][y] = NO_ROUTE;
return false;
}
} else {
return false;
}
}
}
}
public static void main(String[] args) {
// 定义迷宫地图
int[][] map = {
{1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1}
};
// 创建迷宫
Maze maze = new Maze(map, 1, 1, 6, 5);
// 打印地图
System.out.println("地图的情况:");
maze.printMap();
System.out.println("输出新的地图的情况:");
maze.findWay();
maze.printMap();
}
}
地图的情况:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
输出新的地图的情况:
找到一条出迷宫的路~~
1 1 1 1 1 1 1
1 2 0 0 0 0 1
1 2 2 2 0 0 1
1 1 1 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 0 0 1
1 0 0 2 2 2 1
1 1 1 1 1 1 1
class EightQueen {
/**
* 定义有多少个皇后
*/
private int size;
/**
* 定义数组,保存皇后摆放位置的结果,如array = {0, 4, 7, 5, 2, 6, 1, 3}
*/
private int[] array;
/**
* 统计有多少种解法
*/
private List<int[]> schemes = new ArrayList<>(128);
/**
* 冲突次数统计
*/
private int conflictCount = 0;
public EightQueen(int size) {
this.size = size;
this.array = new int[this.size];
}
/**
* 得到所有解
*/
public List<int[]> getAllScheme() {
settingQueen(0);
return schemes;
}
/**
* 获取冲突判断次数
*/
public int getConflictCount() {
return conflictCount;
}
/**
* 放置第n个皇后
* 每一次递归进入到settingQueen,都有for (int i = 0; i < size; i++),因此会有回溯
* @param n 表示第n个皇后
*/
private void settingQueen(int n) {
if (n == size) {
// 得到一个解
print();
return;
}
// 依次放置皇后,并判断是否冲突
for (int i = 0; i < size; i++) {
// 先把当前的皇后n,放置到该行的第i列
array[n] = i;
if (!isConflict(n)) {
// 不冲突,则接着放n+1个皇后
settingQueen(n + 1);
}
// 如果冲突,就继续执行array[n] = i
// 即将第n个皇后,放置到本行的 后移的一个位置
}
}
/**
* 当放置第n个皇后时,就去检测该皇后和前面已摆放的皇后是否冲突
* @param n 表示第n个皇后
* @return true 表示冲突 false 表示不冲突
*/
private boolean isConflict(int n) {
conflictCount++;
for (int i = 0; i < n; i++) {
// 同一列,同一行不需要判断(n==i)
boolean isSameColumn = array[i] == array[n];
// 同一斜线
boolean isSameSlash = Math.abs(n - i) == Math.abs(array[n] - array[i]);
if (isSameColumn || isSameSlash) {
return true;
}
}
return false;
}
/**
* 打印皇后摆放的位置输出
*/
private void print() {
schemes.add(array);
for (int i = 0; i < size; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
}
public class EightQueenDemo {
public static void main(String[] args) {
EightQueen eightQueen = new EightQueen(8);
// 得到所有解
List<int[]> allScheme = eightQueen.getAllScheme();
System.out.printf("一共有 %d 种解法\n", allScheme.size());
System.out.printf("一共有判断冲突 %d 次\n", eightQueen.getConflictCount());
}
}
0 4 7 5 2 6 1 3
0 5 7 2 6 3 1 4
0 6 3 5 7 1 4 2
0 6 4 7 1 3 5 2
1 3 5 7 2 0 6 4
1 4 6 0 2 7 5 3
1 4 6 3 0 7 5 2
1 5 0 6 3 7 2 4
1 5 7 2 0 3 6 4
1 6 2 5 7 4 0 3
1 6 4 7 0 3 5 2
1 7 5 0 2 4 6 3
2 0 6 4 7 1 3 5
2 4 1 7 0 6 3 5
2 4 1 7 5 3 6 0
2 4 6 0 3 1 7 5
2 4 7 3 0 6 1 5
2 5 1 4 7 0 6 3
2 5 1 6 0 3 7 4
2 5 1 6 4 0 7 3
2 5 3 0 7 4 6 1
2 5 3 1 7 4 6 0
2 5 7 0 3 6 4 1
2 5 7 0 4 6 1 3
2 5 7 1 3 0 6 4
2 6 1 7 4 0 3 5
2 6 1 7 5 3 0 4
2 7 3 6 0 5 1 4
3 0 4 7 1 6 2 5
3 0 4 7 5 2 6 1
3 1 4 7 5 0 2 6
3 1 6 2 5 7 0 4
3 1 6 2 5 7 4 0
3 1 6 4 0 7 5 2
3 1 7 4 6 0 2 5
3 1 7 5 0 2 4 6
3 5 0 4 1 7 2 6
3 5 7 1 6 0 2 4
3 5 7 2 0 6 4 1
3 6 0 7 4 1 5 2
3 6 2 7 1 4 0 5
3 6 4 1 5 0 2 7
3 6 4 2 0 5 7 1
3 7 0 2 5 1 6 4
3 7 0 4 6 1 5 2
3 7 4 2 0 6 1 5
4 0 3 5 7 1 6 2
4 0 7 3 1 6 2 5
4 0 7 5 2 6 1 3
4 1 3 5 7 2 0 6
4 1 3 6 2 7 5 0
4 1 5 0 6 3 7 2
4 1 7 0 3 6 2 5
4 2 0 5 7 1 3 6
4 2 0 6 1 7 5 3
4 2 7 3 6 0 5 1
4 6 0 2 7 5 3 1
4 6 0 3 1 7 5 2
4 6 1 3 7 0 2 5
4 6 1 5 2 0 3 7
4 6 1 5 2 0 7 3
4 6 3 0 2 7 5 1
4 7 3 0 2 5 1 6
4 7 3 0 6 1 5 2
5 0 4 1 7 2 6 3
5 1 6 0 2 4 7 3
5 1 6 0 3 7 4 2
5 2 0 6 4 7 1 3
5 2 0 7 3 1 6 4
5 2 0 7 4 1 3 6
5 2 4 6 0 3 1 7
5 2 4 7 0 3 1 6
5 2 6 1 3 7 0 4
5 2 6 1 7 4 0 3
5 2 6 3 0 7 1 4
5 3 0 4 7 1 6 2
5 3 1 7 4 6 0 2
5 3 6 0 2 4 1 7
5 3 6 0 7 1 4 2
5 7 1 3 0 6 4 2
6 0 2 7 5 3 1 4
6 1 3 0 7 4 2 5
6 1 5 2 0 3 7 4
6 2 0 5 7 4 1 3
6 2 7 1 4 0 5 3
6 3 1 4 7 0 2 5
6 3 1 7 5 0 2 4
6 4 2 0 5 7 1 3
7 1 3 0 6 4 2 5
7 1 4 2 0 6 3 5
7 2 0 5 1 4 6 3
7 3 0 2 5 1 6 4
一共有 92 种解法
一共判断冲突 15720 次
/**
* 需求:
* 有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),
* 当输入该员工的id时,要求查找到该员工的 所有信息.
*
* @author yangwei
* @date 2020-05-18 23:16
*/
public class HashTabDemo {
public static void main(String[] args) {
final HashTab hashTab = new HashTab(7);
//写一个简单的菜单
String key = "";
Scanner scanner = new Scanner(System.in);
System.out.println("add: 添加雇员");
System.out.println("list: 显示雇员");
System.out.println("find: 查找雇员");
System.out.println("exit: 退出系统");
while (true) {
key = scanner.next();
switch (key) {
case "add":
System.out.println("输入 id");
int id = scanner.nextInt();
System.out.println("输入名字");
//创建 雇员
String name = scanner.next();
Emp emp = new Emp(id, name);
hashTab.add(emp);
break;
case "list":
hashTab.list();
break;
case "find":
System.out.println("请输入要查找的 id");
id = scanner.nextInt();
hashTab.findById(id);
break;
case "exit":
scanner.close();
System.exit(0);
default:
break;
}
}
}
}
/**
* 哈希表
*/
class HashTab {
private int size;
private EmpLinkedList[] empLinkedLists;
/**
* 构造器
*
* @param size
*/
public HashTab(int size) {
this.size = size;
// 初始化
empLinkedLists = new EmpLinkedList[size];
// 这时不要忘了分别初始化每个链表
for (int i = 0; i < size; i++) {
empLinkedLists[i] = new EmpLinkedList();
}
}
/**
* 添加
*/
public void add(Emp emp) {
// 根据员工的 id ,得到该员工应当添加到哪条链表
int hashVal = hash(emp.id);
empLinkedLists[hashVal].add(emp);
System.out.println("添加 " + emp.toString() + " 成功");
}
/**
* 遍历
*/
public void list() {
for (int i = 0; i < size; i++) {
empLinkedLists[i].list(i+1);
}
}
/**
* 根据id查找
*/
public void findById(int id) {
int hashVal = hash(id);
Emp emp = empLinkedLists[hashVal].findById(hashVal);
if (emp != null) {
System.out.printf("在第 %d 条链表中找到 雇员 id = %d\n", (hashVal + 1), id);
} else {
System.out.println("在哈希表中,没有找到该雇员~");
}
}
private int hash(int id) {
return id % size;
}
}
/**
* EmpLinkedList
*/
class EmpLinkedList {
/**
* 头指针,指向第一个Emp,因此我们这个链表的head是直接指向第一个Emp
*/
private Emp head;
/**
* 添加:假定,当添加雇员时,id 是自增长,即 id 的分配总是从小到大
* 因此我们将该雇员直接加入到本链表的最后即可
*/
public void add(Emp emp) {
if (head == null) {
head = emp;
return;
}
Emp curEmp = head;
while (curEmp.next != null) {
curEmp = curEmp.next;
}
curEmp.next = emp;
}
/**
* 遍历
*/
public void list(int no) {
if (head == null) {
System.out.println("第" + no + "条链表空~~");
return;
}
System.out.print("第" + no + "条链表的信息为:");
Emp curEmp = head;
while (curEmp != null) {
System.out.printf("=> id=%d name=%s\t", curEmp.id, curEmp.name);
curEmp = curEmp.next;
}
System.out.println();
}
/**
* 根据 id 查找雇员
* 如果查找到,就返回 Emp, 如果没有找到,就返回 null
*/
public Emp findById(int id) {
if (head == null) {
System.out.println("链表为空~~");
return null;
}
Emp curEmp = head;
while (curEmp.next != null) {
if (curEmp.id == id) {
// 找到了,此时 curEmp 就指向要查找的雇员
break;
}
curEmp = curEmp.next;
}
return curEmp;
}
}
/**
* 雇员类
*/
class Emp {
public int id;
public String name;
public Emp next;
public Emp(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Emp{id=" + id + ", name=" + name + "}";
}
}
add: 添加雇员
list: 显示雇员
find: 查找雇员
exit: 退出系统
add
输入 id
1
输入名字
Tom
添加 Emp{id=1, name=Tom} 成功
add
输入 id
2
输入名字
Jack
添加 Emp{id=2, name=Jack} 成功
add
输入 id
3
输入名字
Simith
添加 Emp{id=3, name=Simith} 成功
list
第1条链表空~~
第2条链表的信息为:=> id=1 name=Tom
第3条链表的信息为:=> id=2 name=Jack
第4条链表的信息为:=> id=3 name=Simith
第5条链表空~~
第6条链表空~~
第7条链表空~~
add
输入 id
10
输入名字
zhangsan
添加 Emp{id=10, name=zhangsan} 成功
list
第1条链表空~~
第2条链表的信息为:=> id=1 name=Tom
第3条链表的信息为:=> id=2 name=Jack
第4条链表的信息为:=> id=3 name=Simith => id=10 name=zhangsan
第5条链表空~~
第6条链表空~~
第7条链表空~~
find
请输入要查找的 id
10
在第 4 条链表中找到 雇员 id = 10
exit