一、栈

1.特点:栈是先进后出的。
2.数组模拟栈的分析图
三、栈和队列 - 图1
实现 栈的 思路分析

  1. 使用数组来模拟栈

  2. 定义一个 top 来表示栈顶,初始化 为 -1

  3. 入栈的操作,当有数据加入到栈时, top++; stack[top] = data;

  4. 出栈的操作, int value = stack[top]; top—, return value

代码实现栈

  1. public class ArrayStack {
  2. //栈需求实现
  3. private int maxLength;
  4. private int[] stack;
  5. private int top = -1;
  6. public ArrayStack(int maxLength) {
  7. this.maxLength = maxLength;
  8. stack = new int[maxLength];
  9. }
  10. public boolean isFull() {
  11. return top == maxLength - 1;
  12. }
  13. public boolean isEmpty() {
  14. return top == -1;
  15. }
  16. public void push(int val) {
  17. if (isFull()) {
  18. throw new RuntimeException("对不起,已满");
  19. }
  20. top++;
  21. stack[top] = val;
  22. }
  23. public int pop() {
  24. if (isEmpty()) {
  25. throw new RuntimeException("对不起,是空栈");
  26. }
  27. int value = stack[top];
  28. top--;
  29. return value;
  30. }
  31. public void list() {
  32. if (isEmpty()) {
  33. throw new RuntimeException("对不起,是空栈");
  34. }
  35. for (int i = 0; i < stack.length; i++) {
  36. System.out.printf("stack[%d]=%d\t", i, stack[i]);
  37. }
  38. }
  39. //栈中元素存在的个数
  40. public int length(){
  41. return this.top+1;
  42. }
  43. }

判断回文(利用栈)

  1. public class TestApp {
  2. //判断回文
  3. //hello olleh 不是一个回文
  4. public static void main(String[] args) {
  5. System.out.println(detecation("aba"));
  6. }
  7. public static boolean detecation(String val){
  8. ArrayStack arrayStack = new ArrayStack(10);
  9. //获取字符串长度
  10. int length =val.length();
  11. //放入栈
  12. for(int i =0;i<length;i++){
  13. //注意:这里将a转化成97
  14. arrayStack.push(val.charAt(i));
  15. }
  16. //获取
  17. String newVal = "";
  18. int length1=arrayStack.length();
  19. for(int i =0;i<length1;i++){
  20. if(!arrayStack.isEmpty()){
  21. char pop =(char)arrayStack.pop();
  22. newVal=newVal+pop;
  23. }
  24. }
  25. /* equals方法的源代码:
  26. public boolean euqals(Object obj){
  27. return(this==obj);
  28. */
  29. if(val.equals(newVal)){
  30. return true;
  31. }
  32. return false;
  33. }
  34. }

例题:计算机需求分析

三、栈和队列 - 图2

  1. public class ArrayStack {
  2. //栈需求实现
  3. private int maxLength;
  4. private int[] stack;
  5. private int top = -1;
  6. public ArrayStack(int maxLength) {
  7. this.maxLength = maxLength;
  8. stack = new int[maxLength];
  9. }
  10. public boolean isFull() {
  11. return top == maxLength - 1;
  12. }
  13. public boolean isEmpty() {
  14. return top == -1;
  15. }
  16. public void push(int val) {
  17. if (isFull()) {
  18. throw new RuntimeException("对不起,已满");
  19. }
  20. top++;
  21. stack[top] = val;
  22. }
  23. public int pop() {
  24. if (isEmpty()) {
  25. throw new RuntimeException("对不起,是空栈");
  26. }
  27. int value = stack[top];
  28. top--;
  29. return value;
  30. }
  31. public void list() {
  32. if (isEmpty()) {
  33. throw new RuntimeException("对不起,是空栈");
  34. }
  35. for (int i = 0; i < stack.length; i++) {
  36. System.out.printf("stack[%d]=%d\t", i, stack[i]);
  37. }
  38. }
  39. //栈中元素存在的个数
  40. public int length() {
  41. return this.top + 1;
  42. }
  43. //判断是否是一个运算符 + - * /
  44. public boolean isOper(char v) {
  45. return v == '+' || v == '-' || v == '*' || v == '/';
  46. }
  47. //判断运算符优先级,数字越大的优先级越大
  48. public int priority(int oper) {
  49. if (oper == '*' || oper == '/') {
  50. return 1;
  51. } else if (oper == '+' || oper == '-') {
  52. return 0;
  53. } else {
  54. return -1;
  55. }
  56. }
  57. //获取栈顶数据
  58. public int peek() {
  59. return this.stack[top];
  60. }
  61. //获取栈容量
  62. public int stackLength() {
  63. return this.stack.length;
  64. }
  65. /**
  66. * 计算两个数进行运算后的结果
  67. * 2+3
  68. * 3:num1,2:num2
  69. */
  70. public int calculate(int num1, int num2, int oper) {
  71. int result = 0;
  72. switch (oper) {
  73. case '+':
  74. result = num1 + num2;
  75. break;
  76. case '-':
  77. result = num2 - num1;
  78. break;
  79. case '*':
  80. result = num1 * num2;
  81. break;
  82. case '/':
  83. result = num2 / num1;
  84. break;
  85. default:
  86. break;
  87. }
  88. return result;
  89. }
  90. }
  1. public class TestStack {
  2. public static void main(String[] args) {
  3. String str="4+3+2*3-1";
  4. //1、需要遍历字符串,获取每一个字符。
  5. //2、判断当前字符是一个运算符还是数字
  6. //3、把数字放入数字栈,把运算符放入运算符栈
  7. //4、运算符栈:如果是一个空栈,那么运算符直接入栈,如果运算符栈中已经
  8. //有其他运算符就需要先对比运算符优先级,新进来的运算符如果小于等于原栈中运算符,
  9. //那么需要把原运算符弹出来,数字栈中的数字进行弹栈,进行运算,运算后的结果重新
  10. //放入数字栈,新运算符直接入栈,如果新的运算符优先级大于原栈中的运算符,那么运算符直接入栈。
  11. ArrayStack numStack = new ArrayStack(10);
  12. ArrayStack symbolStack = new ArrayStack(10);
  13. //获取字符串的长度
  14. int temp1=0;
  15. int temp2=0;
  16. int symbolChar = 0;
  17. int result = 0;
  18. int length =str.length();
  19. String values = "";
  20. for(int i =0;i<length;i++){
  21. char c =str.charAt(i);
  22. //是否是一个运算符
  23. if(symbolStack.isOper(c)){
  24. if(!symbolStack.isEmpty()){
  25. //比较运算符的优先级
  26. if(symbolStack.priority(c)<=symbolStack.priority(symbolStack.peek())){
  27. //1、去符号栈中获取栈顶的符号
  28. //2、去数字栈中获取两个数字
  29. temp1 = numStack.pop();
  30. temp2 = numStack.pop();
  31. symbolChar = symbolStack.pop();
  32. result= numStack.calculate(temp1,temp2,symbolChar);
  33. //把运算结果再次放入数字栈中
  34. numStack.push(result);
  35. //把当前符号压入符号栈中
  36. symbolStack.push(c);
  37. }else {
  38. symbolStack.push(c);
  39. }
  40. }else{
  41. //如果是空符号栈,将运算结果直接压栈
  42. symbolStack.push(c);
  43. }
  44. }else {
  45. //比如 33+44
  46. values +=c;
  47. if(i==length-1){
  48. numStack.push(Integer.parseInt(values));
  49. }else{
  50. //substring包括起始,不包括终止
  51. char data = str.substring(i+1,i+2).charAt(0);
  52. if(symbolStack.isOper(data)){
  53. numStack.push(Integer.parseInt(values));
  54. values="";
  55. }
  56. }
  57. }
  58. }
  59. while (true){
  60. if(symbolStack.isEmpty()){
  61. break;
  62. }
  63. temp1= numStack.pop();
  64. temp2= numStack.pop();
  65. symbolChar = symbolStack.pop();
  66. result= numStack.calculate(temp1,temp2,symbolChar);
  67. numStack.push(result);
  68. }
  69. int res = numStack.pop();
  70. System.out.println("结果是"+res);
  71. }
  72. }

中缀转后缀表达式

  1. package test;
  2. public class ArrayStack {
  3. //数组的最大长度
  4. private int maxLength;
  5. //定义一个数组
  6. private int[] stack;
  7. //初始化指针为-1
  8. private int top = -1;
  9. //通过构造方法构造数组
  10. public ArrayStack(int maxLength) {
  11. this.maxLength = maxLength;
  12. stack = new int[maxLength];
  13. }
  14. //判断是否满
  15. public boolean isFull() {
  16. //如果top指针与顶端相等则放回为true
  17. return top == maxLength - 1;
  18. }
  19. //判断是否空
  20. public boolean isEmpty() {
  21. //如果top指针与-1相等则放回为true
  22. return top == -1;
  23. }
  24. //入栈
  25. public void push(int val) {
  26. if (isFull()) {
  27. throw new RuntimeException("对不起,已满");
  28. }
  29. //将指针往上移一位
  30. top++;
  31. //将加入的数移动到相应的位置
  32. stack[top] = val;
  33. }
  34. //出栈
  35. public int pop() {
  36. if (isEmpty()) {
  37. throw new RuntimeException("对不起,是空栈");
  38. }
  39. //将这个数保存到一个变量
  40. int value = stack[top];
  41. //指针往下移动一位
  42. top--;
  43. //将这个值返回
  44. return value;
  45. }
  46. }
  1. package test;
  2. public class PostInfix {
  3. /*(在实际代码中我们添加了大于10的数字情况的处理)
  4. 1:从左到右顺序读取表达式中的字符:
  5. 2.是操作数,复制到后缀表达式字符串
  6. 3:是左括号,把字符压入栈中
  7. 4:是右括号,从栈中弹出符号到后缀表达式,直到遇到左括号,然后把左括号弹出。
  8. 5:是操作符,如果此时栈顶操作符优先级大于或等于此操作符,弹出栈顶操作符到后缀表达
  9. 式,直到发现优先级级更低的元素位置,把操作符压入。
  10. 6:读到输入的末尾,将栈元素弹出直到该栈变成空栈,将符号写到后缀表达式中
  11. */
  12. public String doTransfer(String str){
  13. ArrayStack arrayStack = new ArrayStack(20);
  14. StringBuffer stringBuffer = new StringBuffer();
  15. String values="";
  16. char[] chars=str.toCharArray();
  17. // 1:从左到右顺序读取表达式中的字符:
  18. for(int i=0;i<chars.length;i++){
  19. char c = (char)chars[i];
  20. // 1.1是操作符,进行分级操作
  21. if(c=='+'||c=='-'){
  22. doOperation(arrayStack,stringBuffer,c,1);
  23. }else if(c=='*'||c=='/'){
  24. doOperation(arrayStack,stringBuffer,c,2);
  25. //1.2如果是左括号压栈
  26. }else if (c=='('){
  27. arrayStack.push(c);
  28. //1.3如果是右括号...
  29. }else if(c==')'){
  30. doRightBracket(arrayStack,stringBuffer);
  31. // 1.4是操作数,复制到后缀表达式字符串
  32. }else {
  33. values+=c;
  34. char data = str.substring(i+1,i+2).charAt(0);
  35. if(data<49||data>57){
  36. stringBuffer.append(values+",");
  37. values="";
  38. }
  39. }
  40. }
  41. while (!arrayStack.isEmpty()){
  42. stringBuffer.append((char)arrayStack.pop());
  43. }
  44. String news=stringBuffer.toString();
  45. news= news.replace(","," ");
  46. return news;
  47. }
  48. public void doOperation(ArrayStack arrayStack,StringBuffer buffer,char c,int level){
  49. //1.依次从栈顶获取一个值
  50. while(!arrayStack.isEmpty()){
  51. char topc =(char)arrayStack.pop();
  52. //2.这个值跟传入的数据作比较
  53. //2.1栈顶数据是(,不动就是把他压回去
  54. if(topc=='('){
  55. arrayStack.push(topc);
  56. break;
  57. }else {
  58. //首先获取到栈顶元素所对应的级别
  59. int topLevel=0;
  60. if(topc=='+'|| topc=='-'){
  61. topLevel=1;
  62. }else {
  63. topLevel=2;
  64. }
  65. //2.2栈顶数据优先级别大于传入的,输出到后缀表达式
  66. if(topLevel>=level){
  67. buffer.append(topc+",");
  68. break;
  69. }else {
  70. //2.3如果栈顶的优先级小于传入的,不动
  71. arrayStack.push(topc);
  72. break;
  73. }
  74. }
  75. }
  76. //3.找到位置后,把传入的操作符压入
  77. arrayStack.push(c);
  78. }
  79. public void doRightBracket(ArrayStack arrayStack,StringBuffer buffer){
  80. //1.从栈中弹出数据,输出到后缀表达式
  81. while (!arrayStack.isEmpty()){
  82. char topc=(char)arrayStack.pop();
  83. //2.直到遇到"("为止
  84. if(topc=='('){
  85. break;
  86. }else {
  87. buffer.append(topc+",");
  88. }
  89. }
  90. }
  91. public static void main(String[] args){
  92. PostInfix t =new PostInfix();
  93. String s= "(33+3+2)/5-((77+8)*4-5)";
  94. System.out.println("中缀的表现形式:"+s);
  95. String ret=t.doTransfer("(33+3+2)/5-((77+8)*4-5)");
  96. System.out.println("后缀的表现形式"+"res==="+ret);
  97. }
  98. }

image.png

二、队列

1. 队列遵循先入先出原则。放的时候从尾部放,取得时候从 头部取。
K~0PU2_EZN54O6I0KG(I9]I.png

2.环形队列

三、栈和队列 - 图5

1: front变量的含义:front指向队列的第一个元素。 front 的初始值 = 0
2: rear 变量的含义: rear指向队列的最后一个元素的后一个位置。因为希望出一个空间作为约定。 rear 的初始值 = 0
3. 当队列满时,条件是 (rear + 1) % maxSize == front 【满】
4. 对队列为空的条件, rear == front 空
5. 当我们这样分析, 队列中有效的数据的个数 (rear + maxSize - front) % maxSize
6. 我们就可以在原来的队列上修改得到,一个环形队列

3: (7+1)%8==0;
5: (1+8-3)%8=6;

  1. import java.util.Scanner;
  2. public class shuzu_huanxingduilie {
  3. public static void main(String[] args) {
  4. // TODO 自动生成的方法存根
  5. /*
  6. * 用数组来模拟环形队列
  7. * 环形是通过取模(%)来实现的,取模来循环下标,满了就回到原点
  8. * 在上一个代码的基础是进行修改
  9. */
  10. //测试
  11. CircleArray queue = new CircleArray(4);//这里设置4,其有效内存是3,因为最后一个是要空出来的
  12. Scanner scanner = new Scanner(System.in);//获取控制台
  13. char key = ' ';//用来接受用户输入
  14. boolean loop = true;//用来控制系统是否退出
  15. while(loop) {
  16. System.out.println("s(show):显示队列");
  17. System.out.println("e(exit):退出程序");
  18. System.out.println("a(add):添加数据到队列");
  19. System.out.println("g(get):从队列中取出数据");
  20. System.out.println("h(head):查看队列头的数据");
  21. System.out.println("\n请输入指令:");
  22. key = scanner.next().charAt(0);//接收一个字符(0就是一个)
  23. switch(key) {
  24. case's':
  25. queue.showQueue();
  26. break;
  27. case'a':
  28. System.out.println("请输入需要添加的数");
  29. int value = scanner.nextInt();
  30. queue.addQueue(value);
  31. break;
  32. case'g':
  33. try {
  34. int res = queue.getQueue();//上抛了异常,所以要处理异常
  35. System.out.printf("取出的数据是%d\n",res);
  36. }catch(Exception e) {
  37. System.out.println(e.getMessage());
  38. }
  39. break;
  40. case'h':
  41. try {
  42. int res = queue.headQueue();
  43. System.out.println("队列头数据是"+res);
  44. }catch(Exception e) {
  45. System.out.println(e.getMessage());
  46. }
  47. break;
  48. case'e':
  49. scanner.close();//关闭控制台
  50. loop = false;
  51. break;
  52. }
  53. }
  54. System.out.println("程序退出成功!");
  55. }
  56. }
  57. //使用数组模拟队列,编写一个类ArrayQueue类
  58. class CircleArray {
  59. private int maxSize;//表示数组最大容量
  60. private int front;//队列头
  61. private int rear;//队列尾
  62. private int[] arr;//该数组用来存放数据,模拟队列
  63. //创建队列的构造器
  64. public CircleArray(int arrMaxSize) {
  65. maxSize = arrMaxSize;//最大容量
  66. arr = new int[maxSize];//创建数组
  67. front = 0;//指向队列头部,分析出front是指向队列头所在位置(包含)
  68. rear = 0;//指向队列尾的后一位
  69. }
  70. //判断队列是否满
  71. public boolean isFull() {
  72. return rear == maxSize-1;
  73. }
  74. //判断队列是否为空
  75. public boolean isEmpty() {
  76. return rear == front;
  77. }
  78. //添加数据到队列
  79. public void addQueue(int n) {
  80. if(isFull()) {
  81. System.out.println("队列已满,无法添加");
  82. return;
  83. }
  84. arr[rear] = n;//修改队尾所指定的数据为要添加的数据,添加完成
  85. //将rear后移,这里必须考虑取模,避免rear溢出;取模来实现环形
  86. rear = (rear + 1) % maxSize;
  87. }
  88. //获取队列数据,出队列
  89. public int getQueue() {
  90. if(isEmpty()) {
  91. //因为需要返回值,没有数据可取时,可以抛出异常
  92. throw new RuntimeException("队列为空,没有数据可以取出");
  93. }
  94. //这里需要分析出front是指向队列的第一个元素
  95. //1、先把front对应的值保存到一个临时变量
  96. //2、将front后移,需要取模
  97. //将临时变量的值返回(如果前面直接把front的值返回,就没有后移的机会了)
  98. int value = arr[front];
  99. front = (front + 1) % maxSize;//front一直在数组里面,不会溢出,因为已经取模
  100. return value;
  101. }
  102. //打印数组所有数据(队列在其中)
  103. public void showQueue() {
  104. if(isEmpty()) {
  105. System.out.println("队列为空,没有数据可以显示");
  106. return;
  107. }
  108. //思路:从front开始遍历,遍历有效个数size()个
  109. for(int i=front;i<front+size();i++) {
  110. System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
  111. }
  112. }
  113. //求出队列中的有效个数
  114. public int size() {
  115. return (rear + maxSize - front) % maxSize;
  116. }
  117. //显示队列的头数据(是显示,不是取出,还在队列里面)
  118. public int headQueue() {
  119. if(isEmpty()) {
  120. throw new RuntimeException("队列为空,不存在头数据");
  121. }
  122. return arr[front];
  123. }