程序员需要知道的数据结构

特点:先进后出

数据存储:实现栈有两种方式,数组和链表

方法:

push(栈顶添加一个元素)
pop(栈顶删除,并返回删除的元素)
top 返回栈顶的元素,不拿
ISEmpty 判断栈是否为空
Size 返回栈里元素的个数
Clear 清空栈

用数组实现栈:

function Stack(){
var items = []; //存储数据
//此处的items不能用this.items
//因为this可以让items暴漏出来,别人可以直接使用stack.items进行修改

//压栈
this.push = function(item){
    items.push(item)
}

//弹出栈顶元素
this.pop = function(){
     return items.pop()     
}

//返回栈顶元素
this.top = function(){
    return items[items.length-1]
}

//判读栈空
this.isEmpty = function(){
    return items.length === 0;
}

//返回栈的大小
this.size = function(){
    return items.length;
}

//清空栈
this.clear = function(){
    items = [];//不能直接给length赋值,因为length是一个只读属性
}

}

栈的应用

  1. 判断字符串里的括号是否合法,即小括号是否成对出现
    解决方案:遇到左括号,压入栈;遇到右括号,判断栈中是否为空,若为空,说明缺少左括号。直接返回false,如果栈不为空,就把栈顶元素移除,这对括号就抵消了

当循环结束之后,如果栈为空,就说明所有左右括号都抵消掉了,如果栈内还有元素,就说明缺少右括号,字符串括号不合法
//判断字符串里的括号是否合法
function is_legal_brackets(string){
var stack = new Stack();

for(var i=0;i<string.length;i++){
    var item = string[i];
    //遇到左括号就进栈
    if(item == '('){
        stack.push(item);
    }else if(item == ')'){
        //遇到右括号就判断栈是否为空
        if(stack.isEmpty()){
            return false;
        }else{
            stack.pop(item);
        }
    }
}

//如果栈为空,说明字符串合法
return stack.isEmpty();

}
console.log(is_legal_brackets(‘rerer((fdf)d)(d)’))

2…计算后缀表达式
中缀表达式(运算符在两个数中间)4+13/5,-
后缀表达式(运算符在两个数后面) [‘4’,‘13’,‘5’,’/’,’+’]
解决方案:
用for循环遍历每一个字符,如果遇到数字,就压入栈中
如果遇到+=*/,则从栈中弹出两个数字进行计算,并将结果压入栈中
当for循环结束之后,栈中只有一个元素,就是最后的结果

,//计算后缀表达式
function calc_exp(exp){
var stack = new Stack();
for(var i=0;i<exp.length;i++){
var item = exp[i];
console.log(item)
if([’+’,’-’,’*’,’/’].indexOf(item)>=0){
var value1 = stack.pop();
var value2 = stack.pop();
var exp_str = value2+item+value1;
console.log(exp_str)
//计算并取整
var res = parseInt(eval(exp_str))//eval可以直接计算表达式的结果
//计算结果压入栈中
stack.push(res.toString())

    }else{
        console.log('数字')
        stack.push(item)
    }
}
return stack.pop()

}
console.log(calc_exp([‘4’,‘13’,‘5’,’/’,’+’]) )//中缀表达式是4+13/5

练习(面试常见)

面试1:
实现一个栈,除了常见的push,pop方法以外,提供一个min方法,返回栈里最小的元素,时间复杂度为o(1)
解决方案:借助两个栈,一个存放数据,一个存放最小值
//练习题1(面试常见)
function minStack(item){
var dataStack = new Stack();//存放数据
var min_stack = new Stack();//存放最小值

this.push = function(item){
    dataStack.push(item)
    if(min_stack.isEmpty()||item<min_stack.top()){
        min_stack.push(item)
    }else{
        min_stack.push(min_stack.pop())
    }
}
this.pop = function(){
    dataStack.pop();
    min_stack.pop();
}
this.min = function(){
    return min_stack.top()
}

}

var minStack = new minStack();
minStack.push(3)
minStack.push(6)
minStack.push(8)
console.log(minStack.min())
minStack.push(2)
console.log(minStack.min())

面试2:
使用栈,完成中缀表达式转化成后缀表达式
解决方案:
如果是数字,直接放到后缀表达式中;
遇到左括号入栈;遇到右括号,将栈顶元素弹出,直到遇到右括号;
如果遇到运算符,就将栈顶元素弹出,直到栈顶的运算符优先级小于当前运算符,把弹出的运算符加入到后缀表达式中,将当前运算符入栈,
for循环结束后,栈里可能还有元素,都弹出放入到后缀表达式中

//练习题2:中缀表达式转后缀表达式
var priority_map = {
//此处用来定义运算符的优先级
‘+’:1,
‘-’:1,
’:2,
‘/’:2
}
function infix_postfix(infix_exp){
var stack = new Stack();
var postfix_exp = [];
for(var i=0;i<infix_exp.length;i++){
var item = infix_exp[i];
//如果是数字,直接放入到后缀表达中
if(!isNaN(item)){
postfix_exp.push(item)
}else if(item == ‘(’){
//如果遇到左括号,就压入栈中
stack.push(item)
}else if(item == ‘)’){
//如果遇到右括号就将栈顶元素弹出,直到遇到左括号
while(stack.top()!=’(’){
postfix_exp.push(stack.pop())
}
stack.pop();//左括号出栈
}else{
//如果遇到运算符,就把栈顶的运算符弹出,直到栈顶运算符分优先级小于当前优先级
while(!stack.isEmpty()&&[’+’,’-’,’
’,’/’].indexOf(stack.top())>=0
&& priority_map[stack.top()]>= priority_map[item]){
//把弹出的运算符加入到后缀表达式中
postfix_exp.push(stack.pop())
}
//当前运算符入栈
stack.push(item)
}
}
//for循环结束后,栈内可能还有元素,都弹出放入到后缀表达式中
while(!stack.isEmpty()){
postfix_exp.push(stack.pop())
}
return postfix_exp;
}
console.log(infix_postfix([‘4’,’+’,‘13’,’/’,‘5’]));

队列

特点:先进先出

数据存储:使用数组或者链表

方法:

Enquene 队尾添加一个元素
Dequene 队列头部删除一个元素
Head 返回头部的元素,类似于栈中的top
Size 返回队列大小
Clear 清空队列
IsEmpty 判断队列是否为空
Tail 返回队尾节点

用数组实现

function Queue(){
var items = []; //存储数据
//入队操作,向队列尾部添加一个元素
this.enqueue = function(item){
items.push(item)
}
//出队操作,移除队列头部的元素
this.dequeue = function(){
return items.shift()
}
//返回头部的元素
this.head = function(){
return items[0]
}
//返回队列尾部的元素
this.tail = function(){
return items[items.length-1]
}
//返回队列大小
this.size = function(){
return items.length;
}
//清空队列
this.clear = function(){
items = [];
}
//判断是否为空队列
this.isEmpty = function(){
return items.length == 0;
}

}

练习(面试常见)

面试1:约瑟夫环
有一个数组a[100]存放0到99,要求没隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数

思路分析:
可以把 这些数放到队列中去,一个一个往出弹,使用index来标记,如果模3为0,就删除这个元素,否则就把它再放入队列中,直到队列中只有一个元素

面试2:斐波那契
斐波那契数列:1 1 2 3 5 8 13
思路分析:
将两个数1,1放入队列中,出队列一个元素,取队列头部元素,然后将计算结果放入队列中
//斐波那契数列
function fibonacci(n){
var queue = new Queue()
var index = 0;
//先将前两个数值放入队列中
queue.enqueue(1);
queue.enqueue(1);
//求第n项,前面已经放了两个元素,所以此处是n-2
while(index<n-2){
//出队列一个元素
var del_item = queue.dequeue();
//取队列头部元素
var head_item = queue.head();
//将计算结果放入队列中
var next_item = del_item+head_item;
queue.enqueue(next_item);
index+=1;
}
return queue.tail();
}
console.log(fibonacci(7))

面试3:用两个队列实现栈
思路分析
两个队列分别命名为queue1和queue2
Push,实现push时,如果两个队列都为空,默认向queue1里面添加数据,如果有一个不为空,则向这个不为空的队列里面添加
Top,两个队列,或者都为空,或者有一个不为空,只需要返回不为空的队列的尾部元素即可
Pop pop方法删除的是栈顶,但这个栈顶元素其实是队列的队尾。每一次做pop操作时,将不为空的队列里的元素一一删除,并放到另一个队列中直到遇到队列中只剩下一个元素,删除这个元素,其余的元素都跑到了之前为空的队列中了
//用两个队列实现栈
function QueueStack(){
var queue1 = new Queue();
var queue2 = new Queue();
var data_queue = null;//放数据的队列
var empty_queue = null;//空队列,备份使用

    //确认哪个队列放数据,哪个队列做备份
    var init_queue = function(){
        //都为空,默认返回queue1
        if(queue1.isEmpty()&&queue2.isEmpty()){
            data_queue = queue1;
            empty_queue = queue2;
        }else if(queue1.isEmpty()){
            data_queue = queue2;
            empty_queue = queue1;
        }else{
            data_queue = queue1;
            empty_queue = queue2;
        }
    }
}

//push方法
this.push = function (item){
    init_queue();
    data_queue.enqueue(item)
}
//top方法
this.top = function(){
    init_queue();
    data_queue.tail();
}
//pop方法
this.top = function(){
    init_queue();
    while(data_queue.size()>1){
        empty_queue.enqueue(data_queue.dequeue())
        
    }
    return data_queue.dequeue();    
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值