JavaScript数据结构——栈和队列

栈 Stack

栈是先进后出LIFO的线性表,数据进出都在栈顶,另一端叫栈尾。

在web开发中,文本编辑器的“撤消”操作实现了栈的数据组织形式。每次将文本添加到文本编辑器时,该文本被压入栈中。其中第一次添加的文本位于栈底;最后一次的修改位于栈顶。如果用户希望撤销最后一次修改,则删除处于栈顶的那段文本,这个过程可以不断重复,一直到栈中没有更多内容,这时我们会得到一个空白文件。

用JavaScript结合原型实现栈
  • push(data):添加一个或是几个新元素到栈顶。
  • pop():移除栈顶的元素,同时返回被移除元素。
function Stack(){
	this.size = 0
	this.storage= []
}

// 把方法添加到原型对象中
Stack.prototype = {
	push: function(data){
		this.storage[this.size++] = data  // this.size++表示push一个data时size加1
	},
	pop: function(){		
		// 判断如果栈不为空才执行pop
		if(this.size){     
			// 3. 储存被删除元素
			var deleteData = this.storage[this.size]
			
			// 1. 删除栈顶元素
			delete this.storage[this.size]	
			// 2. 栈大小减一
			this.size--
			
			// 4. 返回被删除元素
			return deleteData     
		}
	}
}
语法笔记

(昨天刚刚全面学习了一遍this和原型,这里结合使用巩固一下)

  1. 原型的使用
    因为每一个栈的实例都栈的以上方法,所以它们添加到栈的prototype对象中。把所有对象实例需要共享的属性和方法直接定义在prototype对象上,可以节省内存,每次调用构造函数生成对象时,就不用都创建一遍重复的属性和方法。
  2. this的使用
    在原型对象通过this获取的属性和方法就是构造函数中this的this.size,this.storage,在创建新对象时指向这个新对象。
直接调用js的api实现队列

给栈声明以下方法:

  • push(data):添加一个或是几个新元素到栈顶。
  • pop():移除栈顶的元素,同时返回被移除元素。
  • peek():返回栈顶的元素,但并不对栈顶的元素做出任何的修改。
  • isEmpty():检查栈内是否有元素,如果有返回true,没有返回false。
  • clear():清除栈里的元素。
  • size():返回栈的元素个数。
  • print():打印栈里的元素。
function Stack(){
	this.storage = []

	this.push = function(data){
		this.storage.push(data)
	}

	this.pop = function(){
		return this.storage.pop()
	}
	
	this.peek = function(){
		return this.storage[this.storage.length-1]
	}

	this.isEmpty = function(){
		return this.storage.length == 0
	}
	
	this.size = function(){
		return this.storage.length
	}

	this.print = function(){
		console.log(this.storage.toString())
	}
}
语法笔记
  1. 调用api的写法不能用在原型对象中

队列 Queue

队列是先进先出FIFO的线性表。只允许一端进行插入操作,另一端进行删除操作。

在web开发中,队列的例子是Web浏览器的事件循环。当触发不同事件时,例如单击某个按钮,点击事件将被添加到事件循环队列中,并按照它们进入队列的顺序进行处理。

用JavaScript结合原型实现队列
  • enqueue(data) 将数据添加到队列中。
  • dequeue() 删除最早加入队列的数据。
  • size() 返回队列的长度。
function Queue(){
	// 设置双指针,new用来增加数据,old用来删除数据
	this.OldestIdx = 0
	this.NewestIdx = 0
	this.storage = []
}
Queue.prototype = {
	size: function(){
		return this.NewestIdx - this.OldestIdx + 1
	}
	enqueue: function(data){
		this.storage[this.NewestIdx++] = data
	},
	dequeue:function(){
		// 3. 因为要返回被删的数据,这里要先保存起来
		var deleteData = this.storage[this.OldestIdx]
		
		// 5. 如果两个指针相遇表示队列为空,不能再删
		if (this.OldestIdx != this.NewestIdx){
		
			// 1. 删除旧数据
			delete this.storage[this.OldestIdx]
			// 2. 旧数据指针向前移动
			this.OldestIdx ++
			
			// 4. 返回被删除元素
			return deleteData
		}
	}
}
直接调用js的api实现队列

给队列声明以下方法:

  • enqueue(data):向队列尾部添加一个(或是多个)元素。
  • dequeue():移除队列的第一个元素,并返回被移除的元素。
  • front():返回队列的第一个元素——最先被添加的也是最先被移除的元素。队列不做任何变动。
  • isEmpty():检查队列内是否有元素,如果有返回true,没有返回false。
  • size():返回队列的长度。
  • print():打印队列的元素。
function Queue(){
	this.storage = []

	this.enqueue = function(data){
		this.storage.push(data)
	}

	this.dequeue = function(){
		return this.storage.shift()
	}

	this.front = function(){
		return this.storage[0]
	}

	this.isEmpty = function(){
		return this.storage.length == 0
	}

	this.print = function(){
		console.log(this.storage.toString())
	}
}

练习1 leetcode 232. 用栈实现队列 (easy)

使用栈实现队列的下列操作:

push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

解题思路

  1. 用两个栈实现一个队列,两个栈都是先进后出,队列在两端先进先出,想办法获取一个栈栈尾的元素,放到另一个栈栈顶
    在这里插入图片描述
    在这里插入图片描述
    图摘自负负得正,使用两个栈,一个专门入队,一个专门出队
  2. 关键1.一次性把stackPush的元素都pop出来,即调用了一次pop,stackPush就为空了,那peek方法咋办?为了在不确定数据是在stackPush还是stackPop的时候,调用peek,为了保证得到队首元素,就在peek方法里也操作一次,把所有stackPush里的数据push到stackPop里。前面判断一下,如果stackPop不为空,即前面有操作过这一步骤了,就不用操作。发现有重复使用这一步骤,就封装成一个方法PushtoPop 。
  3. 关键2.因为要判断是否为空的时候才PushtoPop,所以不是每一次执行push方法时都会执行PushtoPop,就要在push和pop中都调用PushtoPop,以防多次pop,使stackPop为空,而stackPush中还有元素。
var MyQueue = function() {
    this.stackPush = []
    this.stackPop = []
};

MyQueue.prototype.PushtoPop = function() {
    // 只要确保stackPop中一定存有stackPush栈尾的值,并将其push在stackPop栈顶即可
    if(this.stackPop.length === 0){		// 关键1
        while(this.stackPush.length > 0){
            this.stackPop.push(this.stackPush.pop())
        }
    }
};

MyQueue.prototype.push = function(x) {
    this.stackPush.push(x)
    this.PushtoPop()	// 关键2
};

MyQueue.prototype.pop = function() {
    if(this.stackPop.length === 0 && this.stackPush.length === 0){
        throw Error ("The queue is empty")
    }
    this.PushtoPop()	// 关键2
    return this.stackPop.pop()
    
};

MyQueue.prototype.peek = function() {
    if(this.stackPop.length === 0 && this.stackPush.length === 0){
        throw Error ("The queue is empty")
    }
 
    this.PushtoPop()	// 关键1
    return this.stackPop[this.stackPop.length - 1]
};

MyQueue.prototype.empty = function() {
    return this.stackPop.length === 0 && this.stackPush.length === 0
};
语法笔记
  1. js中获取数组元素最后一项不能用arr[-1]索引,要用arr[arr.length - 1]
  2. 逻辑运算符的内涵是
    只要“||”前面为false,结果都返回“||”后面的值。
    只要“||”前面为true,结果都返回“||”前面的值。
    只要“&&”前面是false,结果都将返“&&”前面的值;(可以记为返回false)
    只要“&&”前面是true,结果都将返“&&”后面的值;(可以记为根据后面的true false判断)
    但是这样在写的时候就很容易晕,如果只是在boolean判断的时候用逻辑运算符,直接记住
    && 与 两个操作数同时为true,结果为true,否则都是false
    || 或 两个操作数有一个为true,结果为true,否则为false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值