【第二章_数据结构】栈、队列、链表

第一节:解密QQ号-队列

书中描述的过程很详细啊,我直接照着过程自己先写了个

let arr = [6, 3, 1, 7, 5, 8, 9, 2, 4];
let res = [];

while (arr.length > 0) {
    res.push(arr.shift());
    let head = arr.shift();
    if (head) {
        arr.push(head);
    }
}

// 第一次写了个错误版本:死循环
// arr 会一直有一个 undefined 元素
// while (arr.length >= 0) {
//     res.push(arr.shift());
//     arr.push(arr.shift());
// }
console.log(res);

大家可以根据我写的错误,来取取经叭,我个人也要多反思,像这样的错误就是因为程序的边界细节的处理不好,说的简单点就是想得不够周到,多吃核桃吧。

插一嘴:因为写了上面的死循环bug,然后调试到浏览器中,发现打开不了控制台啊,于是写了这篇文章: vscode 配置调试工具 JavaScript 调试

因为js给的方法多,所以写的简洁,我们来实现一下书中的代码:

let q = new Array(102).fill(0);
let init = [0, 6, 3, 1, 7, 5, 8, 9, 2, 4];
for (let i = 0; i < init.length; i++) {
    q[i] = init[i];
}
let head = 1,
    tail = 10;
while (head < tail) {   // 此条件说明队列不为空
    console.log(q[head]);
    head++;         // 模拟队首出队
    
    q[tail] = q[head];
    tail++;         
    
    head++;
}

模拟结构体实现

class Queue{
    constructor(){
        this.data = new Array(100).fill(0);
        this.head = 1;
        this.tail = 10;
    }
}

let q = new Queue();
let init = [0, 6, 3, 1, 7, 5, 8, 9, 2, 4];
for (let i = 0; i < init.length; i++) {
    q.data[i] = init[i];
}
while (q.head < q.tail) {   // 此条件说明队列不为空
    console.log(q.data[q.head]);
    q.head++;         // 模拟队首出队
    
    q.data[q.tail] = q.data[q.head];
    q.tail++;         
    
    q.head++;
}

第二节:解密回文-栈

因为栈的特点,只需要一个指向栈顶的指针了
书中得栗子实例如下:

let s = []; // 栈容器
// let str = "ahaha";
let str = "ahahaa";
let len = str.length;
let mid = (len >> 1) - 1; // 注意这里要减1
let stackTop = 0;
for (let i = 0; i <= mid; i++) {
    s[++stackTop] = str[i];
}
console.log(s); // [empty,a,h,a]
let next;
if (len % 2 == 0) {
    next = mid + 1;
} else {
    next = mid + 2;
}
for (let j = next; j < len; j++) {
    if (str[j] != s[stackTop]) {
        break;
    }
    stackTop--;
}
if (stackTop === 0) {
    console.log("是回文字符串");
} else {
    console.log("不是回文字符串");
}

第三节:纸牌游戏

这个代码有一丢丢长,是栈和队列的应用

let xiaoheng = [2, 4, 1, 2, 5, 6];
let xiaoha = [3, 1, 3, 5, 6, 4];
let book = new Array(10).fill(0);
class Queue {
    constructor() {
        // 这里要写成this,刚开始我写成let了...
        this.data = [];
        this.head;
        this.tail;
    }
}
class Stack {
    constructor() {
        this.data = [];
        this.top;
    }
}
let q1 = new Queue();
let q2 = new Queue();
let s = new Stack();
q1.head = 1;
q1.tail = 1;
q2.head = 1;
q2.tail = 1;
s.top = 0;
for (let i = 1; i <= xiaoheng.length; i++) {
    q1.data[i] = xiaoheng[i - 1];
    q1.tail++;
}
for (let j = 1; j <= xiaoha.length; j++) {
    q2.data[q2.tail] = xiaoha[j - 1];
    q2.tail++;
}

while (q1.head < q1.tail && q2.head < q2.tail) {
    // 小哼出牌
    t = q1.data[q1.head];
    if (book[t] === 0) {
        // 没有赢牌
        q1.head++;
        s.top++;
        s.data[s.top] = t;
        book[t] = 1;
    }
    else {
        q1.head++;
        q1.data[q1.tail] = t;
        q1.tail++;
        while (s.data[s.top] != t) {
            book[s.data[s.top]] = 0;
            q1.data[q1.tail] = s.data[s.top];
            s.top--;
            q1.tail++;
        }
    }

    // 小哈出牌
    t = q2.data[q2.head];
    if (book[t] === 0) {
        // 没有赢牌
        q2.head++;
        s.top++;
        s.data[s.top] = t;
        book[t] = 1;
    }
    else {
        q2.head++;
        q2.data[q2.tail] = t;
        q2.tail++;
        while (s.data[s.top] != t) {
            book[s.data[s.top]] = 0;
            q2.data[q2.tail] = s.data[s.top];
            s.top--;
            q2.tail++;
        }
    }
}
if (q2.head = q2.tail) {
    console.log('小哼win');
    console.log('小哼的手牌是:',q1.data.slice(q1.head, q1.tail));
    // for (let i = q1.head; i <= q1.tail - 1; i++) {
    //     console.log(q1.data[i]);
    // }
    if (s.top > 0) {
        console.log('桌上的牌是:',s.data.slice(1,s.top + 1));
        // for (let i = 1; i <= s.top; i++) {
        //     console.log(s.data[i]);
        // }
    }
} else {
    console.log('小哈win');
    console.log('小哈的手牌是:',q2.data.slice(q2.head, q2.tail));
    // for (let i = q2.head; i <= q2.tail - 1; i++) {
    //     console.log(q2.data[i]);
    // }
    if (s.top > 0) {
        console.log('桌上的牌是:');
        for (let i = 1; i <= s.top; i++) {
            console.log(s.data[i]);
        }
    }
}

第四节:链表

这部分主要的是如何建立链表,具体的思路就是,建立一个节点,然后把前一个节点的next 指向新节点,然后把前一个结点更新。

在看这部分的时候,我就有个疑问:如何把链表连在一起的啊,最关键的一步是q = p;,其中q就记录着前一个节点(我当时没读懂这个才迷惑的)。

// 创建链表
function ListNode(val) {
    this.val = val;
    this.next = null;
}
// 建立链表
let arr = [2, 3, 5, 8, 9, 10, 18, 26, 32];
let head = null;
let q = new ListNode();
for (let i = 0, len = arr.length; i < len; i++) {
    let p = new ListNode(arr[i]);
    p.next = null;
    if (head === null) {
        head = p;
    } else {
        q.next = p;     // 上一个节点的后继指针指向当前创建的节点。
    }
    q = p;      // q是上一个节点
}
console.log(head);
let t = head;
while(t){
    console.log(t.val);
    t = t.next;
}

接下俩讲了如何增添一个节点到链表中,这里插入一个6

function ListNode(val) {
    this.val = val;
    this.next = null;
}
// 建立链表
let arr = [2, 3, 5, 8, 9, 10, 18, 26, 32];
let head = null;
let q = new ListNode();
for (let i = 0, len = arr.length; i < len; i++) {
    let p = new ListNode(arr[i]);
    if (head === null) {
        head = p;
    } else {
        q.next = p;
    }
    q = p;
}
// console.log(head);
let t = head;
while (t) {
    if (t.next.val > 6) {
        let p = new ListNode(6);
        p.next = t.next;
        t.next = p;
        break;
    }
    t = t.next;
}

while (head) {
    console.log(head.val);
    head = head.next;
}

第五节:模拟链表

模拟链表的思想其实都差不多,只是把指针的部分换成数组了。

我们定义一个数组 right,用来保存位置,什么位置呢?当前序列中每一个元素右边的元素在数组 data 中的位置`。很绕对吧?这是书里的原话,emm尝试多读几遍吧!!

let data = [0, 2, 3, 5, 8, 9, 10, 18, 26, 32];
let right = [];
// 初始化right数组
let len = data.length - 1;
for (let i = 1; i < len; i++) {
    right[i] = i + 1;
}
right[len] = 0;

len++;
data[len] = 6;// 插入的数字

let t = 1;  //  t 相当于 index 吧
while (t != 0) {
    // 如果右侧节点大于要插入的节点
    if (data[right[t]] > data[len]) {
        right[len] = right[t];
        right[t] = len;
        break;
    }
    t = right[t];
}
console.log(data, right);

// 读取数字
let t1 = 1;
while (t1) {
    console.log(data[t1]);
    t1 = right[t1];
}

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值