JS数据结构与算法之栈结构

太过爱你忘了你带给我的痛 2024-03-25 10:52 193阅读 0赞

认识栈结构

栈是比较常见的受限的线性结构,栈结构先进后出last in first out

b5059fbc41a580798423a82dd9805faf.png

程序中对栈的使用:

  • 函数调用栈

A函数中调用B,B调用C,C调用D;在A执行的过程中会将A压入栈,随后B执行时B也被压入栈,函数C和D执行时也会被压入栈。所以当前栈的顺序为:A->B->C->D(栈顶);函数D执行完之后,会弹出栈被释放,弹出栈的顺序为D->C->B->A

  • 递归

为什么没有停止条件的递归会造成栈溢出?比如函数A为递归函数,不断地调用自己(因为函数还没有执行完,不会把函数弹出栈),不停地把相同的函数A压入栈,最后造成栈溢出

js栈结构的封装

  1. // 封装栈类
  2. function Stack(){
  3. // 栈中的属性
  4. this.items =[]
  5. // 栈的相关操作
  6. // 1.push():将元素压入栈
  7. //方式一(不推荐):给对象添加方法,其他对象不能复用
  8. // this.push = () => {
  9. // }
  10. //方式二(推荐):给Stack类添加方法,能够多对象复用
  11. Stack.prototype.push = function(element) {
  12. // 利用数组item的push方法实现Stack类的pop方法
  13. this.items.push(element)
  14. }
  15. // 2.pop():从栈中取出元素
  16. Stack.prototype.pop = () => {
  17. // 利用数组item的pop方法实现Stack类的pop方法
  18. return this.items.pop()
  19. }
  20. // 3.peek():查看一下栈顶元素
  21. Stack.prototype.peek = () => {
  22. return this.items[this.items.length - 1]
  23. }
  24. // 4.isEmpty():判断栈是否为空
  25. Stack.prototype.isEmpty = () => {
  26. // 两个小时的教训啊不是this.length(不是Stack对象的length,Stack类没有length属性啊),而是 Stack类中定义的数组items才有length属性呀
  27. return this.items.length == 0
  28. }
  29. // 5.size():获取栈中元素的个数
  30. Stack.prototype.size = () => {
  31. return this.items.length
  32. }
  33. // 6.toString():以字符串形式输出栈内数据
  34. Stack.prototype.toString = () => {
  35. //希望输出的形式:20 10 12 8 7
  36. let resultString = ''
  37. for (let i of this.items){
  38. resultString += i + ' '
  39. }
  40. return resultString
  41. }
  42. }

测试代码

  1. // 栈的使用
  2. let s = new Stack()
  3. s.push(20)
  4. s.push(10)
  5. s.push(100)
  6. s.push(77)
  7. console.log(s) //65
  8. console.log(s.pop()); //68
  9. console.log(s.pop()); //69
  10. console.log(s.peek()); //71
  11. console.log(s.isEmpty()); //72
  12. console.log(s.size()); //74
  13. console.log(s.toString()); //75

js实现判断栈的压入、弹出序列

一道题目:输入两个整数序列,第一个序列表示栈的压入顺序,判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。

例如:1,2,3,4,5是某个栈的压入顺序,序列4,5,3,2,1是该栈对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

用数组来模拟栈的操作。主要思路:

在判断第一个弹出的数字时,如果刚好是入栈的栈顶元素,那么直接弹出。继续从第1步开始判断下一个弹出的数字。

如果不是,则将入栈序列中不为弹出数字的数字压入到辅助栈中直到找到这个弹出元素(若没找到,则直接可以退出,说明弹出序列不可能)。

如果弹出序列存在的话,那么接下来的弹出元素只有两个可能:①出现在入栈的栈顶;②存在于辅助栈中。然后循环判断这两种状况直到弹出栈变为空即可。

如果以上两种情况都没匹配到,那么该弹出序列就不可能了。

  1. /**
  2. * 这里使用JS实现,用数组来模拟栈的操作
  3. * @param {栈输入的顺序(数组表示)} pushOrder
  4. * @param {栈输出的顺序(数组表示)} popOrder
  5. */
  6. function isPopPossible(pushOrder, popOrder) {
  7. var isPossible = false
  8. /** 1. 确认输入的合法性 */
  9. if (pushOrder != null && popOrder != null && Array.isArray(pushOrder) && Array.isArray(popOrder)) {
  10. /** 2. 都为空直接返回true(这里认为两个栈都是空的话,就是true) */
  11. if (pushOrder.length === 0 && popOrder.length === 0) {
  12. return true
  13. }
  14. /** 3. 保证两个输入的序列长度是相等的 */
  15. if (pushOrder.length === popOrder.length) {
  16. /** JS中数组传入的是引用,为了保证不改变原数组,这里创建一份他们的副本 */
  17. var pushOrder_copy = [...pushOrder]
  18. var popOrder_copy = [...popOrder]
  19. /** 这个数组作为辅助的栈 */
  20. var helpStack = []
  21. /** 获取第一个弹出的元素(此时弹出序列减少了一个元素) */
  22. var now = popOrder_copy.shift()
  23. /** 将栈顶不为第一个弹出的元素的元素压入辅助栈 */
  24. while (pushOrder_copy.length > 0 && pushOrder_copy[pushOrder_copy.length - 1] !== now) {
  25. helpStack.unshift(pushOrder_copy.pop())
  26. }
  27. /** 若所有元素都弹出了还没找到和第一个弹出元素相等的元素,则直接返回false */
  28. if (pushOrder_copy.length === 0) {
  29. return false
  30. }
  31. /** 说明找到了,则将匹配到的这个元素弹出 */
  32. pushOrder_copy.pop()
  33. /** 4. 遍历剩下的弹出栈元素(这里入栈序列可能不为空,辅助栈可能不为空,弹出栈可能不为空) */
  34. while (popOrder_copy.length > 0) {
  35. /** 获取下一个弹出元素 */
  36. now = popOrder_copy.shift()
  37. /** 如果入栈序列的栈顶为该弹出元素,则将其从入栈中弹出 */
  38. if (pushOrder_copy.length > 0 && pushOrder_copy[pushOrder_copy.length - 1] === now) {
  39. pushOrder_copy.pop()
  40. } else {
  41. /** 遍历辅助栈,看弹出的元素是否在辅助栈中 */
  42. while (helpStack.length > 0) {
  43. /** 如果辅助栈栈顶的元素不为弹出的元素,则将其压入到入栈中 */
  44. if (helpStack[0] !== now) {
  45. pushOrder_copy.push(helpStack.shift())
  46. } else {
  47. /** 辅助栈中找到了该弹出元素,则将该元素弹出,跳出循环,进行下一轮弹出元素的判断 */
  48. helpStack.shift()
  49. break
  50. }
  51. }
  52. }
  53. }
  54. /** 最终入栈和出栈都为空,说明都匹配到了,则是可能的弹出序列 */
  55. if(popOrder_copy.length === 0 && pushOrder_copy.length === 0) {
  56. isPossible = true
  57. }
  58. }
  59. }
  60. return isPossible
  61. }
  62. /** =====测试用例===== */
  63. /** 1.两个都为空 */
  64. console.log(isPopPossible([], [])) //true,
  65. /** 2.其中一个不存在 */
  66. console.log(isPopPossible(null, [])) //false
  67. /** 3.元素个数不匹配 */
  68. console.log(isPopPossible([1, 2, 3, 4], [1, 2, 3])) //false
  69. /** 4.元素不匹配 */
  70. console.log(isPopPossible([1, 2, 3, 4], [1, 2, 3, 5])) //false,
  71. /** 5.比较常规的测试 */
  72. console.log(isPopPossible([1, 2, 3, 4, 5], [4, 5, 3, 2, 1])) //true
  73. /** 5.不匹配 */
  74. console.log(isPopPossible([1, 2, 3, 4, 5], [4, 5, 3, 1, 2])) //false
  75. /** 6.入栈的序列为空,都在辅助栈中 */
  76. console.log(isPopPossible([1, 2, 3, 4, 5], [5, 4, 3, 2, 1])) //true,
  77. /** 7. 输入栈和辅助栈来回交替 */
  78. console.log(isPopPossible([1, 3, 2, 0], [1, 2, 0, 3])) //true

利用栈结构实现十进制转二进制

  1. //简单应用:
  2. //封装函数:将十进制转成二进制(十转二的运算最后倒叙取余的特点符合栈'先进后出')
  3. let dec2bin = decNumber => {
  4. //1.定义一个栈对象,保存余数
  5. var stack = new Stack()
  6. // 2.循环操作
  7. while(decNumber > 0){
  8. // 2.1.获取余数并放入栈中
  9. stack.push(decNumber % 2)
  10. // 2.2.获取整除后的结果作为下一次运算的数字(floor:向下取整)
  11. decNumber = Math.floor(decNumber / 2)
  12. }
  13. // 3.从栈中取出0和1
  14. let binaryString = '';
  15. let a = stack.items.length
  16. while(stack.items.length != 0){
  17. binaryString += stack.pop();
  18. }
  19. return binaryString;
  20. }
  21. //测试代码
  22. console.log(dec2bin(10)); //103
  23. console.log(dec2bin(100)); //104
  24. console.log(dec2bin(1000)); //105

发表评论

表情:
评论列表 (有 0 条评论,193人围观)

还没有评论,来说两句吧...

相关阅读

    相关 02【JS数据结构算法

    写在前面 上一节我们介绍了JS中的第一个数据结构——数组,包括它里面的一些自带的方法、还有我们自己手动实现的方法、还有使用场景等。JS中的数组跟其他语言不太一样,它是动态

    相关 数据结构算法

    数据结构与算法 栈 一、简述       栈是一种只能在一端进行插入或删除操作的线性表。进行插入、删除的一端称为栈顶,栈顶的当前位置是动态的,由一个称为栈顶指针的位置指

    相关 JS 数据结构算法—— & 队列

    写在前面 原计划是把《你不知道的Javascript》三部全部看完的,偶然间朋友推荐了数据结构与算法的一套入门视频,学之。发现数据结构并没有想象中那么遥不可及,反而发觉挺有意

    相关 数据结构算法

    前言 在前面几篇我们有讲到数组,链表等数据结构,这些都是存储数据的最基本的结构。而本篇文章讲解的则是利用算法和数据结构来实现一些小工具,来解决现实中某种需求。它就是栈。