数据结构与算法学习——栈,队列,优先级队列及封装其方法

什么是数据结构以及有什么作用?

数据结构是计算机存储.组织数据的方式。
数据存储只有一个目的,即为了方便后期对数据的再利用。因此,数据在计算机存储空间的存放,决不是胡乱的,这就要求我们选择一种好的方式来存储数据,而这也是数据结构的核心内容。

生活中的例子就比如图书馆一样,每个书架排放这不同类型的书籍或者以其他分类,能够更快速的找到我们想要找的书。

解决问题方法的效率,跟数据的组织方式有关
计算机中存储的数据量相对于图书馆的书籍来说数量更大,种类更多
以什么样的方式来存储和组织我们的数据才能在使用数据时更加方便
这就是数据结构需要考虑的问题

常见的数据结构

队列/树/堆/数组/栈/链表/图/散联表

什么是算法

一个有限指令集,每条指令的描述不依赖语言
接受一些输入(有些情况下不需要输入)
产生输出
一定在有限步骤之后终结

他是一种受限的线性表,后进先出
其限制是仅允许在表的一端进行插入和删除运算。这一段被称为栈顶,相对的把另一端成为栈底
LIFO(last in first out)表示就是后进入的元素,第一个弹出栈空间。类似于托盘,最后放上的托盘,往往先被拿出去使用
向一个栈插入新元素又称作进栈。入栈或压栈,他是把新元素放到栈顶元素的上面,使之成为新的栈顶元素
从一个栈删除元素又称为出栈或推栈,他是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

那么就让我们基于数组来实现一个栈内存的方法:
push(ele) 添加一个新元素到栈顶位置
pop 移除栈顶的元素,同时返回被移除的元素
peek 返回栈顶的元素,不对栈进行任何修改
isEmpty 如果栈里没有元素就返回true,否则返回false
Size 返回栈里的元素个数,这个方法和数组的length相似
toString 将栈结构的内容以字符形式返回

 class Stack {
    constructor() {
      this.items = []
    }

    push(ele) {
      this.items.push(ele)
    }

    pop() {
      return this.items.pop()
    }

    Peek() {
      return this.items[this.items.length - 1]
    }

    isEmpty() {
      return this.items.length > 0 ? false : true
    }

    size() {
      return this.items.length
    }

    toString() {
      return this.items.join('')
    }
  }
  //测试
 let stack = new Stack();
    stack.push('1');
    stack.push('2');
    stack.push('3');
    //入栈
    alert(stack);
    //删除栈顶元素
    alert(stack.pop());
    //查看栈顶元素
    alert(stack.Peek());
    //判断栈内存是否为空
    alert(stack.isEmpty());
    //查看栈内存中的数量
    alert(stack.size());
    //转换成字符串
    alert(stack.toString());

上面的不难理解,我们已经使用数组模拟出了栈内存中的方法,那么我们现在基于栈内存中的方法实现一个十进制转换二进制的方法:

  function decimalToBinary(num) {
    let stack = new Stack();
    while (num > 0) {
      stack.push(num % 2);
      num = Math.floor(num / 2);
    }
    let str = '';
    while (!stack.isEmpty()) {
      str += stack.pop()
    }
    return str
  }
  console.log(decimalToBinary(1000));//1111101000
关于栈的面试题
有6个元素6,5,4,3,2,1的顺序进栈,问下列哪一个不是合法的出栈序列 (C)
A 5 4 3 6 1 2 
//6入栈 5入栈 5出栈 4入栈 4出栈 3入栈 3出栈 6出栈 2入栈 1入栈 1出栈 2出栈(是合理的出栈规则)
B 4 5 3 2 1 6
//6入栈 5入栈 4入栈 4出栈 5出栈 3入栈 3出栈 2入栈 2出栈 1入栈 1出栈 6出栈(是合理的出栈规则)
C 3 4 6 5 2 1 
//6入栈 5入栈 4入栈 3入栈 3出栈 4出栈 这里让6出栈它的栈顶目前是5,栈内存只能从栈顶出栈 所以这项选择不成立
D 2 3 4 1 5 6
//6入栈 5入栈 4入栈 3入栈 2入栈 2出栈 3出栈 4出栈 1入栈 1出栈 5出栈 6出栈(是合理的出栈规则)

队列

队列(Queue),它是一种受限的线性表,先进先出(FIFO first in first out)受限之处在于它只允许在表的前端(front)进行删除,而表的后端进行插入操作

生活中的类似的队列结构
比如电影院,商场排队 优先排队的人优先处理

队列有哪些常见的操作?
enqueue(element):向队列尾部添加一个(或多个新的项)
dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素
front():返回队列中第一个元素——最先被添加,也将是最先被移除的元素。队列不作任何变动(不溢出元素,只返回元素信息————与Stack类的peek方法非常相似)
isEmpty():如果队列中不包含任何元素,返回true,否则返回false
Size():返回队列包含的元素个数,与数组的length属性相似
toString():将队列中的内容,转成字符串形式;

好,套路还是那个套路,我们还是基于数组的形式来封装一个队列的方法

class Queue {
    constructor() {
      this.items = []
    }
    enqueue(ele) {
      this.items.push(ele)
    }
    dequeue() {
      return this.items.shift()
    }
    front() {
      return this.items[0]
    }
    isEmpty() {
      return this.items.length > 0 ? false : true
    }
    size() {
      return this.items.length
    }
    toString() {
      return this.items.join('')
    }}
   let queue = new Queue();
   queue.enqueue('1'); //加入队列
   queue.enqueue('2'); //加入队列
   queue.enqueue('3'); //加入队列
   alert(queue);//加入队列后
   alert(queue.dequeue()); //删除队列第一个元素
   alert(queue.front()); //查看队列第一个元素
   alert(queue.isEmpty());//查看队列是否为空
   alert(queue.size());  //查看队列的数量
   alert(queue.toString()); //转换字符串
基于队列实现击鼓传花算法
  function hitTransFlower(ary, num) {
    let queue = new Queue();
    for (let i = 0; i < ary.length; i++) {
      queue.enqueue(ary[i])
    }
    while (queue.size() > 1) {
      for (let j = 0; j < num - 1; j++) {
        queue.enqueue(queue.dequeue());
      }
      queue.dequeue();
    }
    let val = queue.front();
    let index = ary.findIndex(v => v === val);
    return {val, index}
  }
  let ary = [4, 2, 6, 1, 8];
  console.log(hitTransFlower(ary, 3));//{index:3,val:1}

优先级队列

优先级队列的特点:
我们知道,普通的队列插入一个元素,数据会被放在后端,并且需要前面所有的元素都处理完成后才会处理前面的数据
但是优先级队列,在插入一个元素的时候会考虑该数据的优先级
和其他数据优先级进行比较
比较完成后,可以得到这个元素的队列中的正确位置
其他处理方式,和基本队列的处理方式一样
优先级队列主要考虑的问题:
每个元素不再只是一个数据,而且包含数据的优先级
再添加方式中,根据优先级放入正确的位置

封装优先级队列
class Obj {
    constructor(ele, n) {
      this.ele = ele
      this.n = n
    }
  }
  class PriorityQueue {
    constructor() {
      this.items = [];
    }
    enqueue(ele, n) {
      let p = new Obj(ele, n);
      if (this.items.length < 1) {
        this.items.push(p);
      } else {
        for (let i = this.items.length - 1; i >= 0; i--) {
          if (p.n > this.items[i].n) {
            this.items.splice(i + 1, 0, p);
            break;
          }
          if (i === 0) {
            this.items.unshift(p)
          }
        }
      }
   }
}
  let priorityQueue = new PriorityQueue();
  priorityQueue.enqueue('小明', 80);
  priorityQueue.enqueue('小男', 70);
  priorityQueue.enqueue('小航', 100);
  priorityQueue.enqueue('小郑', 60);
  priorityQueue.enqueue('小强', 99);
  console.log(priorityQueue);

志不强者智不达

阅读 109

推荐阅读