闻理似悟,遇境则迷!!!
栈与队列来说也算是一种特殊的线性表,栈的特点是后进先出,队列的特点是先进先出。


栈的特点是后进先出,栈的操作只有出栈和入栈(也叫压栈),除此之外,还包含栈顶与栈底的指向以及栈的长度。
因此栈的定义如下

public class ZStack {
/**
* 栈顶指向
/
private int top = 0;
/
*
* 栈底指向
/
private int bottom = 0;
/
*
* 栈长度
/
public int length = 0;
/
*
* 栈内数据
*/
private Object[] datas;

/*** 栈内最大空间*/
public int MAX_SIZE = 100;/*** 出栈** @return*/
public Object pop() {// 栈顶与栈底指向同一个位置if (top == 0) {return null;} else {// 栈顶下移top--;// 取出栈顶数据Object data = datas[top];// 栈顶置为空datas[top] = null;length--;return data;}
}/*** 入栈** @param o*/
public void push(Object o) {if (top < MAX_SIZE){datas[top] = o;top++;length++;}else {throw new OutOfMemoryError("栈已满,不能再加了");}}// 初始化栈
public ZStack() {// 默认栈长度为100datas = new Object[MAX_SIZE];
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
进制转换(十进制转二进制)
将十进制转为二进制
第一步,将该数除以二,取余,将余数入栈
第二步,重复第一步,直到最后除数为0或者1
第三步,依次出栈,最后的顺序就是二进制数
例如 11转为二进制
11 %2 = 5.,…1
5 % 2 = 2…1
2 % 2 =1…0
入栈顺序 1 1 0 1,最后输出 1 0 1 1,验证一下,1 + 2 +0 +8 = 11
核心代码如下

// 初始化栈
ZStack zStack = new ZStack();
while (num > 0) {
// 余数入栈
zStack.push(num % 2);
num = num / 2;
if (num == 1) {
zStack.push(num);
num = 0;
}
}
// 出栈,打印出二进制内容
StringBuffer sb =new StringBuffer();
while (zStack.length > 0) {
sb.append(zStack.pop());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
中缀表达式转后缀表达式
逆波兰表达式就是后缀表达式,举个例子吧,我们要计算1+(2-3)*4,转为后缀表达式就是 1 2 3 - 4 * +,怎么来的呢
计算规则如下:
第一步,如果是数字,直接输出
第二步,如果是表达式符号,入栈,入栈需要对符号优先级进行判断,如果当前运算符优先级小于栈顶元素,需要先出栈顶元素,然后再入栈
第三步,如果是(,直接入栈,
第四步,如果是),依次出栈,直到遇到(或者栈为空
第五步,将栈内剩余符号出栈
例子,
1>>> 栈 [],输出(1)
+>>>栈[+],输出(1)
(>>>栈[+ ,( ],输出(1)
2>>>栈[+ ,( ],输出(1 2)
->>>栈[+ ,( ,- ],输出(1 2)
3>>>栈[+ ,(, - ],输出(1 2 3)
)>>> 栈[+],输出(1 2 3 -)
× >>> 栈[+,×],输出(1 2 3 -)
4 >>> 栈[+,×],输出(1 2 3 - 4)
最后输出(1 2 3 - 4 + ×)

1+(2*3 - 4)/ 1
1>>> 栈 [],输出(1)
+>>>栈[+],输出(1)
(>>>栈[+ ,( ],输出(1)
2>>>栈[+ ,( ],输出(1 2)
× >>>栈[+ ,(,× ],输出(1 2)
3 >>>栈[+ ,(,× ],输出(1 2 3)
_ >>>栈[+ ,(,- ],输出(1 2 3 ×)注意,×出栈了
4 >>>栈[+ ,(,- ],输出(1 2 3 × 4)
) >>>栈[+ ],输出(1 2 3 × 4 -)
/ >>>栈[+ ,/ ],输出(1 2 3 × 4 -)
1>>>栈[+ ,/ ],输出(1 2 3 × 4 -1)
最后输出1 2 3 × 4 -1/+
验证
在这里插入图片描述
核心代码

private static String parseSuffixExpression(String next) {
StringBuffer suffixSb = new StringBuffer();
char[] chars = next.toCharArray();
ZStack zStack = new ZStack();
for (int i = 0; i < chars.length; i++) {
char thisChar = chars[i];
// 判断字符是否是数字,如果是数字,直接输出
if (Character.isDigit(thisChar)) {
suffixSb.append(thisChar);
} else if (thisChar == ‘)’) {
/**
* 当入栈时是)时,栈为空时依次出栈,栈不为空依次出栈,直到遇到(停止
/
// 栈为空
if (zStack.length == 0) {
zStack.push(thisChar);
} else {
Object pop = zStack.pop();
while (pop != null && !String.valueOf(pop).equals("(")) {
suffixSb.append(pop);
pop = zStack.pop();
}
}
} else if (thisChar == ‘+’ || thisChar == ‘-’) {
/
*
* 当为+,或者-入栈时,需要与栈顶元素的优先级比较,优先级高的需要先出栈,直到遇到(或者栈为空
*/
// 栈为空,直接push
if (zStack.length == 0) {
zStack.push(thisChar);
} else {

                Object pop = zStack.pop();while (pop!=null && !String.valueOf(pop).equals("(")){suffixSb.append(pop);pop = zStack.pop();}/*** (出栈了,需要重新入栈,重点*/if (String.valueOf(pop).equals("(")){zStack.push("(");}zStack.push(thisChar);}} else if (thisChar == '*' || thisChar == '/' || thisChar == '(') {/*** 为* ,/,( 直接入栈*/zStack.push(thisChar);} else {System.err.println("输入错误");}}/*** 输出栈内其它元素*/while (zStack.length!=0) {suffixSb.append(zStack.pop());}return suffixSb.toString();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
RPN(逆波兰表达式)
上面介绍了中缀表达式转后缀表达式(波兰表达式),这里主要是讲波兰表达式如何计算为我们想要的值,以上面例子讲解计算规则
一句来说就是,数字入栈,遇到运算符将栈顶两个元素出栈,运算后再入栈。
例 1 2 3 × 4 -1/+
前3为数字 栈 1 2 3
× >>> 栈1 6
4 >>>> 栈 1 6 4
->>> 1 2
1>>> 1 2 1
/ >>>1 2
+ 1+2 = 3(结果)
与上图结果吻合
核心代码

/**
* 逆波兰表达式计算器,输入的是一个波兰表达式
* @param next
/
private static void rpn(String next) {
if (!next.isEmpty()) {
ZStack zStack = new ZStack();
char[] chars = next.toCharArray();
for (int i = 0; i < chars.length; i++) {
char thisChar = chars[i];
// 判断字符是否是数字,如果是数字,就入栈
if (Character.isDigit(thisChar)) {
zStack.push(thisChar);
} else {
// 先出的是后面的操作数
Double behind = Double.parseDouble(String.valueOf(zStack.pop()));
Double front = Double.parseDouble(String.valueOf(zStack.pop()));
switch (thisChar) {
case ‘+’:
zStack.push(front + behind);
break;
case ‘-’:
zStack.push(front - behind);
break;
case '
’:
zStack.push(front * behind);
break;
case ‘/’:
if (behind == 0) {
throw new NumberFormatException(“被除数不能为0”);
}
zStack.push(front / behind);
break;
default:
break;
}
}
}
System.out.println(next + “计算结果为:” + zStack.pop());

    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
这里还有很多bug,例如,只支持10以内的计算(一个字符),还有一些特殊输入没有判断,反正我是比较满意的,哈哈。

队列
队列是一种先进先出的数据结构。就像我们在食堂打饭排队一样,每次入队列都在队尾操作,每次出队列就在队头操作。使用java代码实现如下,队列使用链式存储结构实现比较好,我这里采用的是顺序存储结构,通过队头队尾形成一个环状队列。

/**

  • 队列类实现(顺序存储实现)
    */
    public class ZQueue {
    // 当前队列长度
    private int length = 0;
    // 队列最大长度
    private int MAX_SIZE = 5;
    // 队列数据
    private Object[] datas;

    /**

    • 队头索引
      /
      private int head = 0;
      /
      *
    • 队尾索引
      */
      private int tail = 0;

    /**

    • 出队列操作
    • @return
      /
      public Object delete() {
      Object returnObj = new Object();
      if (head == tail) {
      if (datas[head] == null) {
      System.err.println(“队列已空,不能出队列”);
      ;
      } else {
      returnObj = datas[head];
      datas[head] = null;
      }
      } else {
      /
      *
      * 队列头置为空,将头往后移
      */
      returnObj = datas[head];
      datas[head] = null;
      head = (head + 1) % MAX_SIZE;
      }
      length–;
      return returnObj;
      }

    /**

    • 入队列操作
      */
      public void add(Object obj) {
      if (length == MAX_SIZE) {
      System.err.println(“队列已满,不能入队”);
      } else {
      // 队尾累加,如果到顶了,头尾相接,再从头开始,形成一个循环队列
      datas[tail++ % MAX_SIZE] = obj;
      length++;
      }
      }

    public ZQueue() {
    this.datas = new Object[MAX_SIZE];
    }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
主类

ZQueue zQueue = new ZQueue();
zQueue.add(“1”);
zQueue.add(“2”);
zQueue.delete();
zQueue.add(“3”);
zQueue.add(“4”);
zQueue.add(“5”);
zQueue.add(“6”);
Object delete = zQueue.delete();
zQueue.add(“7”);
1
2
3
4
5
6
7
8
9
10
运行结果
在这里插入图片描述
以上就是栈与队列相关的操作,最后附上git地址: https://gitee.com/zhoujie1/data-structure-and-algorithm.git
顺便提一个有趣的事情,昨天一前端同事问道将一堆数组平均分成3份的问题,当时我脑海里闪过通过通过快慢指针的方式,定义3个指针,一个指针每次+1,一个指针每次+2,一个指针每次+3,当走得最快的指针到达数组结尾,剩余两个指针的位置就将整个数据分成了3份,从而达到了目的。此时我也深深的感受到了算法的魅力,也坚定了我往下走的决心。

数据结构与算法之栈与队列:java实现相关推荐

  1. 数据结构与算法--利用栈实现队列

    利用栈实现队列 上一节中说明了栈的特点 后进先出,我们用数组的方式实现了栈的基本操作api,因此我们对栈的操作是不考虑排序的,每个api的操作基本都是O(1)的世界,因为不考虑顺序,所以找最大,最小值 ...

  2. 【数据结构与算法】栈与队列

    栈 一.什么是栈? 1.后进者先出,先进者后出,这就是典型的"栈"结构. 2.从栈的操作特性来看,是一种"操作受限"的线性表,只允许在端插入和删除数据. 二.为 ...

  3. 数据结构与算法(二) 栈与队列(代码示例)

    数据结构与算法 栈与队列 1. 数组和链表实现栈 2. 用O(1)的时间复杂度求栈中的最小元素 3. 链表和数组实现队列 4. 用两个栈模拟队列操作 1. 数组和链表实现栈 链表的方式: /*** 描 ...

  4. 数据结构与算法(2)——栈和队列

    前言:题图无关,只是好看,接下来就来复习一下栈和队列的相关知识 前序文章: 数据结构与算法(1)--数组与链表(https://www.jianshu.com/p/7b93b3570875) 栈 什么 ...

  5. 【数据结构与算法】栈与队列【C语言版】

    目录 3.1 栈和队列的定义和特点 3.2 栈.队列与一般线性表的区别 3.3 栈的表示和操作的实现 顺序栈与顺序表 ================= 顺序栈的表示 顺序栈初始化 判断顺序栈是否为空 ...

  6. 用JS描述的数据结构及算法表示——栈和队列(基础版)

    前言:找了上课时数据结构的教程来看,但是用的语言是c++,所以具体实现在网上搜大神的博客来看,我看到的大神们的博客都写得特别好,不止讲了最基本的思想和算法实现,更多的是侧重于实例运用,一边看一边在心里 ...

  7. 数据结构与算法 | 用栈实现队列

    之前的几章我讲解了栈和队列的基本特性和一些基本的操作方法,那么如何能利用栈来实现队列呢? 下面我来讲解下具体思路,栈的特性先进后出,队列是先进先出,如果要模拟队列的这个特性,我们就必须用到两个栈. 一 ...

  8. Python数据结构与算法(六)--栈和队列

    栈和队列 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素.访问元素.删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据( ...

  9. python数据结构和算法3 栈、队列和排序

    顺序表和链表都是线性表,线性数据 栈 stack,也叫堆栈,是一种容器,可存入元素.访问元素.删除元素,特点是只允许在容器的一端(栈顶,top)进行加入数据(压栈,push)和输出数据(pop),按照 ...

最新文章

  1. 常见虚拟主机目录对照及星外提权目录
  2. WINCE6.0添加微软简体中文输入法3.0
  3. c++ 分析core文件 在os x
  4. 为什么 Python 3 把 print 改为函数?
  5. HDU3400+三分
  6. 金蝶系统服务器要求,金蝶服务器安装及其相关要求.doc
  7. Ubuntu安装Google浏览器
  8. 毕昇 JDK:为啥是ARM 上超好用的 JDK
  9. Node路由简单的处理
  10. 定时关机win10_长按电源键强制关机,真的会弄坏电脑吗?
  11. 在Windows系统上安装PHP工作环境
  12. 【数字IC】深入浅出理解UART协议
  13. [微信小程序]搜索功能实现,搜索框样式
  14. Microsoft Edge浏览器使用时过滤网页广告弹窗等插件推荐---电脑初始维护
  15. 国际会议latex/overleaf模板
  16. vmware15pro
  17. 安装数据库显示参考服务器错误日志,Sql Server安装出错,安装程序配置服务器失败的解决方法小结...
  18. linux下gperf工具(tcmalloc)检查C/C++代码内存泄露问题操作说明
  19. android平板灵敏度,和平精英iPad最稳灵敏度怎么设置
  20. 禾川HCQ+X3E ModBUS 电机远程启动

热门文章

  1. 学习TeXworks编辑器(二)TAB补全详解与自定义补全命令总结
  2. SQL Server between...and...语句使用举例
  3. 由于找不到appvisvsubsystems32.dll_ftp软件搜索不到,ftp软件搜索不到的2种原因
  4. CMD执行命令出现NOMALY: meaningless REX prefix used以及IDEA提示Cannot run git问题解决
  5. flume数据采集_大数据采集系统Flume集群部署
  6. python123百钱买百鸡_day01笔记-百钱买百鸡(100文钱,必须买100只鸡,有几种方式)
  7. python网站用什么数据库_使用python读取mysql数据库并进行数据的操作
  8. python3连接oracle 11G数据库
  9. c++date数据类型_PLC编程设涉及到的数据类型了解一下
  10. java 缓存行填充_缓存伪共享问题以及解决方案缓存行填充