数组是一种线性结构,可在数组的任意位置插入和删除数据,而栈和队列就是比较常见的受限的线性结构。
栈
后进先出,限制是仅允许在表的一端进行插入(进栈)和删除(出栈)运算,这一端称为栈顶,另一端称为栈底。
栈结构面试题
有六个元素6,5,4,3,2,1的顺序进栈(并不是一次性,可以一边入栈一边出栈),问下列哪一个不是合法的出栈序列(C)?
A. 5,4,3,6,1,2 B.4 5 3 2 1 6 C.3 4 6 5 2 1 D.2 3 4 1 5 6
解法:1.把脖子右转90度,自己观察
代码实现栈
栈常见的操作:
push(element):添加一个新元素到栈顶位置;
pop():移除栈顶的元素,同时返回被移除的元素;
peek():返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它);
isEmpty():如果栈里没有任何元素就返回true,否则返回false;
size():返回栈里的元素个数。这个方法和数组的length属性类似;
toString():将栈结构的内容以字符串的形式返回。
- 基于数组
function Stack(){
//栈中的属性
this.items = []
// 栈的相关操作
// 1.将元素压入栈
this.push=function(item){
this.items.push(item)
}
// 2.从栈中取出元素
this.pop = function(){
return this.items.pop()
}
// 3.查看一下栈顶元素
Stack.prototype.peek = function(){
// 注意:这种直接在原型链上写方法,比上面的方式节省内存
return this.items[this.items.length-1]
}
// 4.判断栈是否为空
Stack.prototype.isEmpty = function(){
return this.items.length==0
}
// 5.获取栈中元素的个数
Stack.prototype.size = function(){
return this.items.length
}
// 6.toString方法
Stack.prototype.toString = function(){
var resString = ''
for(var i = 0;i < this.items.length;i ++){
resString += this.items[i]+' '
}
return resString
}
}
- 基于链表(性能与基于数组相差不大)
栈的应用
- 十进制转二进制
function dec2bin(decNumber){
var stack = new Stack()
while(decNumber>0){
stack.push(decNumber % 2)
decNumber = Math.floor(decNumber/2)
}
var binNumber = ''
while(!stack.isEmpty()){
binNumber += stack.pop()
}
return binNumber
}
队列
先进先出,受限之处在于只允许在表的前端进行删除,后端进行插入
应用:
打印队列:计算机打印多个文件的时候,需要排队打印;
线程队列:当开启多线程时,当新开启的线程所需的资源不足时就先放入线程队列,等待CPU处理;
代码实现队列
队列常见的操作:
enqueue(element):向队列尾部添加一个(或多个)新的项;
dequeue():移除队列的第一(即排在队列最前面的)项,并返回被移除的元素;
front():返回队列中的第一个元素——最先被添加,也将是最先被移除的元素。队列不做任何变动(不移除元素,只返回元素信息与Stack类的peek方法非常类似);
isEmpty():如果队列中不包含任何元素,返回true,否则返回false;
size():返回队列包含的元素个数,与数组的length属性类似;
toString():将队列中的内容,转成字符串形式;
- 基于数组
function Queue(){
// 属性
this.items = []
// 方法
Queue.prototype.enqueue=function(element){
this.items.push(element)
}
Queue.prototype.dequeue=function(){
return this.items.shift()
}
Queue.prototype.front=function(){
return this.items[0]
}
Queue.prototype.isEmpty=function(){
return this.items.length == 0
}
Queue.prototype.size=function(){
return this.items.length
}
Queue.prototype.toString=function(){
var resString = ''
for(var i = 0;i < this.items.length;i ++){
resString += this.items[i]+' '
}
return resString
}
}
- 基于链表(性能好)
队列面试题
击鼓传花:几个人围成一圈数数,数到某个数字自动淘汰,问最后剩下的人在原来哪一个位置上
function passGame(nameList,num){
console.log(1)
// 1.创建一个队列结构
var queue = new Queue()
// 2.将所有人一次加入到队列中
for(var i = 0;i < nameList.length;i ++){
queue.enqueue(nameList[i])
}
// 3.开始数数字
// 不是num的时候,重新加入到队列的末尾
// 是num这个数字时,将其从队列中删除
while(queue.size!=1){
for(var j = 0;j < num-1;j ++){
// num数字之前的人重新放到队尾
queue.enqueue(queue.dequeue())
}
queue.dequeue()
}
// 获取剩下的那个人
console.log(queue.size());
var endName = queue.front()
console.log(endName)
return nameList.indexOf(endName)
}
优先级队列
优先级队列需要考虑的问题:
- 每个元素不再只是一个数据,而且包含数据的优先级
- 在添加方式中,根据优先级放入正确的位置
优先级队列的应用
- 机场的登场顺序
- 医院的候诊室
- 计算机中,可通过优先级队列排序线程执行的顺序
优先级队列的实现
function PriorityQueue() {
// 类的内部再封装一个类
function QueueElement(element, priority) {
this.element = element
this.priority = priority
}
// 属性
this.items = []
// 方法
PriorityQueue.prototype.enqueue = function (element, priority) {
// 1、创建QueueElement对象
var newElement = new QueueElement(element, priority)
var len = this.items.length
// 2.判断队列是否为空
if (len == 0) {
this.items.push(newElement)
} else {
var added = false
// 该变量用来记录是否前面已找到插入位置
for (var i = 0; i < len; i++) {
if (this.items[i].priority > priority) {
this.items.splice(i, 0, newElement)
added = true
}
}
if(!added){
this.items.push(newElement)
}
}
}
PriorityQueue.prototype.dequeue = function () {
return this.items.shift()
}
Queue.prototype.front = function () {
return this.items[0]
}
PriorityQueue.prototype.isEmpty = function () {
return this.items.length == 0
}
Queue.prototype.size = function () {
return this.items.length
}
PriorityQueue.prototype.toString = function () {
var resString = ''
for (var i = 0; i < this.items.length; i++) {
resString += this.items[i] + ' '
}
return resString
}
}
用两个栈实现一个队列
思想:
入队过程:将元素放入 inStack 中。
出队过程:
outStack 不为空:弹出元素
outStack 为空:将 inStack 元素依次弹出,放入到 outStack 中(在数据转移过程中,顺序已经从后入先出变成了先入先出)
var inStack = [], outStack = []
function push(node) {
inStack.push(node)
}
function pop() {
if(outStack.length){
return outStack.pop()
}else{
while(inStack.length){
outStack.push(inStack.pop())
}
return outStack.pop()
}
}