第3章“栈”
数组是计算机科学中最常用的数据结构,上一章我们学习了如何创建和使用它。我们知道,
可以在数组的任意位置上删除或添加元素。然而,有时候我们还需要一种在添加或删除元素时有
更多控制的数据结构。有两种数据结构类似于数组,但在添加和删除元素时更为可控。它们就是栈和队列
栈是一种遵从后进先出(LIFO—Last-In-First-Out)原则的有序集合。新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端就叫栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底
栈也被用在编程语言的编译器和内存中保存变量、方法调用等
一.栈的创建
- 我们将创建一个类来表示栈。让我们从基础开始,先声明这个类:
//先声明这个类:
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
}
- 我们的栈声明一些方法。
push(element(s)) :添加一个(或几个)新元素到栈顶。
pop() :移除栈顶的元素,同时返回被移除的元素。
peek() :返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返
回它)。
isEmpty() :如果栈里没有任何元素就返回 true ,否则返回 false 。
clear() :移除栈里的所有元素。
size() :返回栈里的元素个数。这个方法和数组的 length 属性很类似 - 实现push方法
这个方法负责往栈里添加新元素,
有一点很重要:该方法只添加元素到栈顶,也就是栈的末尾
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
}
//测试类
var s =new Stack();
s.push("aa");
s.push("bb");
- 实现 pop 方法
这个方法主要用来移除栈里的元素。栈遵从LIFO原则,因此移
出的是最后添加进去的元素
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
this.pop = function(){
return items.pop();
};
}
//测试类
var s =new Stack();//测试push
s.push("aa");
s.push("bb");
var popped = s.pop();
console.log(popped);//bb展示要删除的元素是什么
- 只能用 push 和 pop 方法添加和删除栈中元素,这样一来,我们的栈自然就遵从了LIFO原则
- 为我们的类实现一些额外的辅助方法。如果想知道栈里最后添加的元素是什么,可以用 peek 方法。这个方法将返回栈顶的元素:
因为类内部是用数组保存元素的,所以访问数组的最后一个元素可以用 length - 1 :
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
this.peek = function(){
return items[items.length-1];
};
}
//测试类
var s =new Stack();//测试push
s.push("aa");
s.push("bb");
var peeked = s.peek();
console.log(peeked);//bb
- 辅助方法:isEmpty ,如果栈为空的话将返回 true ,否则就返回 false :
使用 isEmpty 方法,我们能简单地判断内部数组的长度是否为0。
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
this.isEmpty = function(){
return items.length == 0;
};
}
//测试类
var s =new Stack();//测试push
s.push("aa");
s.push("bb");
var isEmptyed = s.isEmpty();
console.log(isEmptyed);//false
- 类似于数组的 length 属性,我们也能实现栈的 length 。对于集合,最好用 size 代替 length 。
因为栈的内部使用数组保存元素,所以能简单地返回栈的长度:
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
this.size = function(){
return items.length;
};
}
//测试类
var s =new Stack();//测试push
s.push("aa");
s.push("bb");
var sizeed=s.size();
console.log(sizeed);//2
- clear 方法 clear 方法用来移除栈里所有的元素,把栈清空。实现这个
方法最简单的方式是
function Stack() {
//1.各种属性和方法的声明
var items = [];//1.1需要一种数据结构来保存栈里的元素。可以选择数组
// 1.2接下来,要为我们的栈声明一些方法
this.push = function(element){
items.push(element);
console.log(items);
};
this.size = function(){
return items.length;
};
this.clear = function(){
items = [];
};
}
//测试类
var s =new Stack();//测试push
s.push("aa");
s.push("bb");
var isclear = s.clear();
var sizeed=s.size();
console.log(sizeed);//2
清空栈还可以:多次调用 pop 方法,把数组中的元素全部移除,这样也能实现 clear 方法
- 辅助方法:print 它会把栈里的元素都输出到控制台:
this.print = function(){
console.log(items.toString());
};
以上的push和pop还有几个辅助方法完成“创建栈”
- 栈的全部代码
function Stack() {
var items = [];
this.push = function(element){
items.push(element);
};
this.pop = function(){
return items.pop();
};
this.peek = function(){
return items[items.length-1];
};
this.isEmpty = function(){
return items.length == 0;
};
this.size = function(){
return items.length;
};
this.clear = function(){
items = [];
};
this.print = function(){
console.log(items.toString());
};
}
- 使用 Stack 类
首先,我们需要初始化 Stack 类。然后,验证一下栈是否为空(输出是 true ,因为还没有往栈里添加元素)。
function Stack() {
var items = [];
this.isEmpty = function(){
return items.length == 0;
};
}
var stack =new Stack();//
console.log(stack.isEmpty());//true
function Stack() {
var items = [];
// 判断栈是否为空
this.isEmpty = function(){
return items.length == 0;
};
// 往栈里添加的元素
this.push = function(element){
items.push(element);
console.log(items)
};
// 往栈里添加的最后一个元素
this.peek = function(){
return items[items.length-1];
};
// 栈里有多少个元素
this.size = function(){
return items.length;
};
// 移除
this.pop = function(){
return items.pop();
};
// 打印栈现在的元素有哪些
this.print = function(){
console.log(items.toString());
};
}
var stack =new Stack();//
console.log(stack.isEmpty());//true
stack.push(5);
stack.push(8);
console.log(stack.peek());//输出8.因为它是往栈里添加的最后一个元素
stack.push(11);
console.log(stack.size());//3
console.log(stack.isEmpty()); //输出false
stack.pop();
console.log(stack.size()); //输出2
stack.print();//5,8
二.从十进制到二进制(栈的应用)
- 十进制转成二进制
function ten2two(num) {
let rem , arr = [],res = '';
while(num){
rem = num % 2;
arr.push(rem);
num = Math.floor(num/2);
}
while(arr.length) {
res += arr.pop();
}
return res;
}
console.log(ten2two(10));//1010
- 十进制转任意进制
//十进制转化为任意进制
function transfer1(num,base) {
return num.toString(base);
}
console.log(transfer1(10,2));//1010
console.log(transfer1(10,8));//12
function transfer2(num,base) {
let arr = [],res = '',rem,digits = '0123456789ABCDEF';
while(num){
rem = num % base;
arr.push(rem);
num = Math.floor(num/base);
}
while(arr.length) {
res += digits[arr.pop()];
}
return res;
}
console.log(transfer2(10,2));//1010
console.log(transfer2(10,8));//12