数据结构学习笔记-栈以及应用

104 阅读2分钟

栈的理解

栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快,而且容易实现。栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。栈被称为一种后入先出(LIFO,last-in-first-out)的数据结构。由于栈具有后入先出的特点,所以任何不在栈顶的元素都无法访问。为了得到栈底的元 素,必须先拿掉上面的元素。

栈的封装

function Stack() {
    // 属性
    this.items = [];
    //  方法 
    // 1将元素加入栈中
    Stack.prototype.push = function (elment) {
        this.items.push(elment);
    }
    // 2从栈中取元素
    Stack.prototype.pop = function () {
        this.items.pop();
    }
    // 3 查看栈顶(底)元素
    Stack.prototype.peek = function () {
        return this.items[this.items.length - 1];
    }
    // 4 队列是否为空
    Stack.prototype.isEmpty = function () {
        return this.items === 0;
    }
    // 5查看队列中的元素个数
    Stack.prototype.size = function () {
        return this.items.length;
    }
    // 6 toString方法
    Stack.prototype.toString = function () {
        let res = '';
        for (let i = 0; i < this.items.length; i++) {
            res += this.items[i] + ' ';
        }
        return res;
    }
}
let s = new Stack()
s.push(1);
s.push(10);
s.push(100);
s.push(1000);

// console.log(s)  //  [1, 10, 100, 1000]

s.pop()
// console.log(s) // [1, 10, 100]

alert(s.peek())  // 100

alert(s.toString()) // 1 10 100 

应用- 将十进制数转二进制

 // 将十进制数转二进制
function toBinaryNumber(number) {
    // 1 将取模的数推入栈
    let stack = [];
    // 获取每次除以2的整数结果  大于0就继续循环
    while (number > 0) {
        stack.push(number % 2);
        number = Math.floor(number / 2);
    }
    // 返回字符串结果  -反转
    let res = stack.reverse().join('')
    return res
}
let t = toBinaryNumber(100)
console.log(t) // 1100100
<p> 100 ---> 二进制 ---> 1100100</p>
<p> 100 % 2 -> 0  --->栈底</p>
<p> 50 %  2 -> 0</p>
<p> 25 %  2 -> 1</p>
<p> 12 %  2 -> 0</p>
<p> 6 %   2 -> 0</p>
<p> 3 %   2 -> 1</p>
<p> 1 %   2 -> 1   ---> 栈顶</p>

<p> 结果是从下往上 1100100</p>

应用-旋转数组k次

 /**
    输入: nums = [1,2,3,4,5,6,7], k = 3
    输出: [5,6,7,1,2,3,4]
    解释:
    向右轮转 1 步: [7,1,2,3,4,5,6]
    向右轮转 2 步: [6,7,1,2,3,4,5]
    向右轮转 3 步: [5,6,7,1,2,3,4]
*/
 // 0(n^2)
var rotate2 = function (nums, k) {
    const length = nums.length;
    if (length === 0 || !k) return nums;
    for(let i=0;i<k;i++) {
        let n = nums.pop();
        if(n != null) {  // 注意元素为0的时候  if(0) 
            nums.unshift(n)   // 数组是一个有序结构,unshift操作非常慢 O(n)
        }
    }
    return nums;
};
let arr2 = [1, 2, 3, 4, 5, 6, 0]
let l2 = rotate2(arr2, 3)
console.log(l2)  // [5,6,0,1,2,3,4]
 // O(n)
var rotate1 = function (nums, k) {
    const length = nums.length;
    if (length === 0 || !k) return nums;
    const step = Math.abs(k % length)
    let arr1 = nums.slice(-step)
    let arr2 = nums.slice(0, length - step);
    let arr3 = arr1.concat(arr2);
    return arr3
};
let arr = [1, 2, 3, 4, 5, 6, 7]
let l = rotate1(arr, 3)
console.log(l)  // [5,6,7,1,2,3,4]

应用- 有效的括号

var checkValid = function (left, right) {
    if (left === '(' && right === ')') return true;
    if (left === '{' && right === '}') return true;
    if (left === '[' && right === ']') return true;
    return false
}
var isValid = function (s) {
    const length = s.length;
    if (length % 2 === 1) return false;  // 括号成对出现,是偶数
    let stack = [];
    let leftSmbols = '([{';
    let rightSmbols = ')]}';
    for (let i = 0; i < length; i++) {
        const str = s[i];
        if (leftSmbols.includes(str)) {
            stack.push(str)  // 入栈
        } else if (rightSmbols.includes(str)) {
            let lastStr = stack[stack.length - 1]; // 最后一位来判断  后进先出一一对应
            if (checkValid(lastStr, str)) {
                stack.pop()  // 出栈    后进先出
            } else {
                return false
            }
        }
    }
    return stack.length === 0;
}
let s = '({([{}])})';
console.log(isValid(s))