数据结构(一):数组、栈、队列、优先级队列

一、栈

先进后出,后进先出

在这里插入图片描述

1. 封装一个栈类

//封装栈类
class Stack {
    constructor() {
        // 存放栈中的元素
        this.items = [];
    }
    //栈的相关操作
    //1.push():压栈操作,添加新元素到栈顶
    //在类中,方法写出来就是直接添加到该类的原型对象上
    push(element) {
        this.items.push(element);
    }
    //2.从栈中取出元素,pop在数组中是删除最后一个元素,返回该元素
    pop() {
        return this.items.pop();
    }
    //3.查看栈顶元素
    peek() {
        return this.items[this.items.length - 1];
    }
    //4.判断栈是否为空
    isEmpty() {
        return this.items.length === 0;
    }
    //5.获取栈中元素个数
    size() {
        return this.items.length;
    }
    //6.toString方法转字符串
    toString() {
        return this.items.join('-');
    }
}

测试代码:

let stack = new Stack();
stack.push('zzy');
stack.push(18);
stack.push('ht');
console.log(stack);
stack.pop();
console.log(stack.peek()); //18
console.log(stack.isEmpty()); //false
console.log(stack.size());//2
console.log(stack.toString()); //zzy-18

测试结果:

在这里插入图片描述

2. 栈的简单应用

用栈实现一个十进制转二进制的函数

//用栈封装一个十进制转二进制的算法
//思路:除以2取余,余数依次入栈,然后依次取出栈顶元素
function dec2bin(decNumber) {
    //1.生成一个栈的实例
    let stack = new Stack();
    //2.循环取余入栈,不确定循环次数,用while
    while (decNumber > 0) {
        // 2.1.获取余数并放入栈中
        stack.push(decNumber % 2);
        // 2.2.获取整除后的结果作为下一次运算的数字(floor:向下取整)
        decNumber = Math.floor(decNumber / 2);
    }
    //3.去除栈顶元素,拼接字符串(任何类型和字符串相加都会变成字符串)
    let result = '';
    while(!stack.isEmpty()) {
        result += stack.pop();
    }
    return result;
}
console.log(dec2bin(100));
console.log(dec2bin(10));
console.log(dec2bin(1000));

测试结果:

在这里插入图片描述

二、队列

先进先出,后进后出
在这里插入图片描述

1. 封装一个队列类

//队列结构的封装
class Queue {
     constructor() {
         //属性
         this.items = [];
     }

     //方法
     //1.将元素添加到队列中
     enqueue(element) {
         this.items.push(element);
     }

     //2.从队列中删除前端元素,并返回该元素
     dequeue() {
         return this.items.shift();
     }

     //3.查看前端的元素
     front() {
         return this.items[0];
     }
     //4.查看队列是否为空
     isEmpty() {
         return this.items.length === 0;
     }
     //5.查看队列中元素的个数
     size() {
         return this.items.length;
     }
     //6.toString方法
     toString() {
         return this.items.join('');
     }
 }

测试代码:

 let queue = new Queue();
 queue.enqueue('abc');
 queue.enqueue(6);
 queue.enqueue(8);
 console.log(queue);
 queue.dequeue();  //删除abc
 console.log(queue);
 console.log(queue.front());  //6
 console.log(queue.isEmpty());  //false
 console.log(queue.size());  //2
 console.log(queue.toString());  //'68'

测试结果:
在这里插入图片描述

2. 队列的简单应用

利用队列实现击鼓传花

击鼓传花规则:围成一圈数数,比如规定数到5的人淘汰,那么淘汰的人后面的人从1开始数,然后数到5的人再淘汰,以此类推,直到剩下最后一个人,求该人的位置。

思路:围成一圈的话,可以看成一个队列,从第一个人开始数,那么在数到num之前的人可以依次从队头删除,加入队尾(保持环形结构)。直到被数到的这个人到队头,然后把它删除就行了。

以上循环依次进行,直到队列只剩一个元素,返回该元素和它的位置

//击鼓传花,规定数到几的人淘汰,然后下一个人从1开始数,数到该数字淘汰
//求最后剩下的那个人的位置,传入参数(名字列表,数字)
function passGame(nameList, num) {
    //1.定义一个队列,并依次把元素加入队列
    let queue = new Queue();
    for(let i = 0; i < nameList.length; i++) {
        queue.enqueue(nameList[i]);
    }
    console.log('初始队列元素:',queue.items);
    //2.从第一个人开始数数
    while(queue.size() > 1) {
        //3.1依次把num之前的数字从队头取出,放到队尾
        for(let i = 0; i < num - 1; i++) {
            queue.enqueue(queue.dequeue());
        }
        //3.2删除第一个元素(数到num的人)
        queue.dequeue();
        console.log(`人数变化:`,queue.items);
    }
    //4.把剩下那个人的名字和位置找出来
    let leftBoy = queue.front();
    let index = nameList.indexOf(leftBoy);
    console.log(`剩下的哥们儿是${leftBoy},他的初始位置是:${index}`);
    return index;
}
passGame(['张三','李四','王五','赵六','田七','郭八'], 6);

3.封装优先级队列

(1)这是什么东西?

所谓优先级队列,其实就是有人可以插队。那么封装的时候队列中元素应该是带着一个优先级标识,标识nb的元素就可以往前靠。也就是说需要有两个参数,分别是element(元素)priority(优先级标识)

(2)封装的逻辑

在这里插入图片描述

大概的思路就是
1、先声明一个内部元素类,用来存储(元素,优先级)两个属性
2、封装优先级队列,继承前面的Queue中的属性和方法(通过super关键字)
3、重写插入方法。

重写的逻辑:
(1)首先判断是否为空,空就直接队尾插入;
(2)不为空,就要遍历当前队列元素,插入的新值依次比较,如果新值优先级较低,那么就使用splice插入到当前位置的前面(把其他的顶到后面),同时跳出循环。
(3)如果比较完之后新插入元素优先级最高,那么直接插入到队尾。

(3)封装代码

封装代码如下:

//优先队列内部的元素类
class QueueElement {
    constructor(element, priority) {
        this.element = element;
        this.priority = priority;
    }
}

//封装优先级队列
class PriorityQueue extends Queue {
    constructor() {
        super(); //super关键字调用父类的构造函数
    }
    //重写enqueue方法
    enqueue(element, priority) {
        //1.根据传入的元素,创建一个元素对象实例
        let queueElement = new QueueElement(element, priority);
        //2.1判断队列是否为空,如果为空那么直接push进去
        if (this.isEmpty()) {
            this.items.push(queueElement);
        } else {
            //2.2如果不为空,那么比较优先级(这里默认小的优先)
            let added = false;  //定义一个标识,判断是否已经插入
            for (let i = 0; i < this.items.length; i++) {
                //3.如果插入的元素优先级更小,那么就在当前位置插入(其他的被挤到后面)
                if (queueElement.priority < this.items[i].priority) {
                    this.items.splice(i, 0, queueElement);
                    added = true; //插入完成,修改标识
                    break; //如果插入完成,就跳出循环
                }
            }
            //4.如果遍历结束后,新元素始终最大,那么就添加到队尾
            if(!added) {
                this.items.push(queueElement);
            }
        }
    }

    //其他方法全部继承(转字符串需要小改)
    dequeue() {
        return super.dequeue(); //super关键字调用父类的函数
    }

    front() {
        return super.front();
    }

    isEmpty() {
        return super.isEmpty();
    }

    size() {
        return super.size();
    }

    toString() {
        let result = "";
        for(let item of this.items) {
            result += `${item.element}-${item.priority} `;
        }
        return result;
    }
}

测试:

//测试代码
const queue = new PriorityQueue();
queue.enqueue('zzy',10);  //参数1为元素,参数2为优先级
queue.enqueue('nba',50);
queue.enqueue('cba',20);
queue.enqueue('dj',40);
queue.enqueue('ht',30);
console.log(queue.items);
console.log(queue.toString()); //zzy-10 cba-20 ht-30 dj-40 nba-50 

(4)几个注意点

1、类的继承,super()直接调用相当于调用的是父类中的constructor函数,也就是说子类调用super相当于直接继承父类的属性(不调用super会报错)。

2、类的继承,如果要在子类中调用父类的方法,要使用super.方法名()

3、关于splice的用法,splice(位置,删除几个,替换的元素),splice(1,0,‘Tom’):表示在索引为1的元素前面插入元素’Tom‘(也可以理解为从索引为1的元素开始删除,删除0个元素,再在索引为1的元素前面添加元素’Tom’);

4、关于splice的用法,splice(1,1,‘Tom’):表示从索引为1的元素开始删除(包括索引为1的元素),共删除1个元素,并添加元素’Tom’。即把索引为1的元素替换为元素’Tom’。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值