這是第二週的練習題,這裡補充下咯,五一節馬上就要到了,自己的計劃先安排上了,開發一個有趣的玩意兒。
下面是之前分享的連結:
本週練習內容:資料結構與演算法 —— Queue
這些都是資料結構與演算法,一部分方法是團隊其他成員實現的,一部分我自己做的,有什麼其他實現方法或錯誤,歡迎各位大佬指點,感謝。
一、佇列有什麼特點,生活中有什麼例子?
解題:
1.概念介紹
佇列,又稱為佇列(queue),是先進先出(FIFO, First-In-First-Out)的線性表。在具體應用中通常用連結串列或者陣列來實現。佇列只允許在後端(稱為rear)進行插入操作,在前端(稱為front)進行刪除操作。 ——《維基百科》
佇列特點:先進先出操作。
生活中的案例:常見的排隊,在電影院也好,排隊結賬也是,排在第一位的人會先接受服務。
2.與堆疊區別
佇列的操作方式和堆疊類似,唯一的區別在於佇列只允許新資料在後端進行新增。
二、請實現一個佇列,並實現以下方法:
enqueue(element)
:向佇列尾部新增一個新的項。dequeue()
:移除佇列的第一項,並返回被移除的元素。front()
:返回佇列中第一個元素 —— 最先被新增,也將是最先被移除的元素。佇列不做任何變動 (不移除元素,只返回元素資訊 —— 與Stack
類的peek
方法類似)。tail()
:返回佇列中的最後一個元素,佇列不做任何變動。isEmpty()
:如果棧沒有任何元素就返回true
,否則返回false
。size()
:返回佇列包含的的元素個數,與陣列的length
屬性類似。print()
:列印佇列中的元素。
提示:Web 端優先使用 ES6 以上的語法實現。
解題:
/**
* 2. 實現一個佇列
*/
class Queue {
constructor (){
this.items = []
}
// enqueue(element):向佇列尾部新增一個新的項。
enqueue( element ){
this.items.push(element)
}
// dequeue():移除佇列的第一項,並返回被移除的元素。
dequeue (){
return this.items.shift()
}
// front():返回佇列中第一個元素 —— 最先被新增,也將是最先被移除的元素。佇列不做任何變動 (不移除元素,只返回元素資訊 —— 與 Stack 類的 peek 方法類似)。
front (){
return this.items[0]
}
// tail():返回佇列中的最後一個元素,佇列不做任何變動。
tail (){
return this.items[this.items.length]
}
// isEmpty():如果棧沒有任何元素就返回 true,否則返回 false。
isEmpty (){
return this.items.length === 0
}
// size():返回佇列包含的的元素個數,與陣列的 length 屬性類似。
size (){
return this.items.length
}
// print():列印佇列中的元素。
print (){
console.log(this.items.toString())
}
}
複製程式碼
三、使用佇列計算斐波那契數列的第 n 項。
斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610...
複製程式碼
在數學上,斐波那契數列以如下被以遞推的方法定義:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N),即前兩項固定為 1*,後面的項為前兩項之和,依次向後。在現代物理、準晶體結構、化學等領域,斐波納契數列都有直接的應用。
使用示例如下:
fibonacci(5); --> 5
fibonacci(9); --> 34
fibonacci(14); --> 377
複製程式碼
解題:
解題方法1:
/**
* 3. 使用佇列計算斐波那契數列的第 n 項。
* 前兩項固定為 1,後面的項為前兩項之和,依次向後。
* @param {Number} num
*/
function fibonacci (num){
if(isNaN(num) || num < 0 || num === 0) return 0
// // 1. 直接
// let n1 = 1, n2 = 1, sum
// for(let i = 3; i <= num; i++){
// sum = n1 + n2
// n1 = n2
// n2 = sum
// }
// // 2. 佇列 考慮小於等於2
// let arr = [], sum
// num === 1 && (arr = [1])
// num >= 2 && (arr = [1, 1])
// for(let i = 3; i <= num; i ++){
// sum = arr[i-2] + arr[i-3]
// arr.push(sum)
// }
// // 3.佇列 進出佇列
let queue = [], sum;
for(let i = 1; i <= num; i ++){
if(i <=2 ){
queue.push(1)
}else{
sum = queue[0] + queue[1]
queue.push(sum)
queue.shift()
}
}
return sum
}
複製程式碼
解題方法2:
function fibonacci(n) {
const queue = new Queue();
queue.enqueue(1);
queue.enqueue(1);
let index = 0;
while(index < n - 2) {
index += 1;
// 出佇列一個元素
const delItem = queue.dequeue();
// 獲取頭部值
const headItem = queue.front();
const nextItem = delItem + headItem;
queue.enqueue(nextItem);
}
return queue.tail();
}
console.log(fibonacci(9)); // 34
複製程式碼
四、實現優先佇列 PriorityQueue。
現實中優先佇列的例子很多,比如機場登機的順序,頭等艙和商務艙乘客優先順序高於經濟艙乘客。又如在銀行中辦理業務時,VIP 客戶的優先順序高於普通客戶。要實現一個優先佇列,有兩種方式:
- 設定優先順序,然後在正確的位置新增元素。
- 用入列操作新增元素,然後按照優先順序移除它們。
本題要求使用第一種方式來實現優先佇列,數值越小優先順序越高,若優先順序相同時,先入隊的元素,排在前面。
使用示例如下:
let priorityQueue = new PriorityQueue();
priorityQueue.enqueue("leo", 2);
priorityQueue.enqueue("pingan", 1);
priorityQueue.enqueue("robin", 1);
priorityQueue.print();
// pingan - 1
// robin - 1
// leo - 2
複製程式碼
解題:
解題方法1:
class PriorityQueue {
constructor() {
this._items = [];
}
enqueue(element, priority) {
let queueElement = {
element
priority
};
if (this.isEmpty()) {
this._items.push(queueElement);
} else {
let added = false;
for (var i = 0; i < this.size(); i++) {
if (queueElement.priority < this._items[i].priority) {
this.items.splice(i, 0, queueElement);
added = true;
break ;
}
}
if (!added) {
this._items.push(queueElement);
}
}
}
print() {
var strArr = [];
strArr = this._items.map(function (item) {
return `${item.element}->${item.priority}`;
});
console.log(strArr.toString());
}
}
複製程式碼
解題方法2:
/**
* 4. 實現優先佇列
*/
class PriorityQueue {
constructor (){
this.items = []
}
enqueue (element, priority){
let ele = {element, priority}
let isAdded = false
for(let i = 0; i < this.items.length; i++){
if(ele.priority < this.items[i].priority){
this.items.splice(i, 0, ele)
isAdded = true
break
}
}
!isAdded && this.items.push(ele)
}
print (){
for(let i = 0; i < this.items.length; i++){
let {element, priority} = this.items[i]
console.log(`${element} - ${priority}`)
}
}
}
let leo = new PriorityQueue()
leo.enqueue("leo", 2);
leo.enqueue("leo1", 1);
leo.enqueue("leo2", 1);
console.log(leo)
複製程式碼
五、用佇列實現棧。
利用兩個佇列實現棧,棧的特點是後進先出,可以讓元素入隊 q1
,留下隊尾元素讓其他元素出隊,暫存到 q2
中,再讓 q1
中剩下的元素出隊,即最後進的最先出來。
提示:入棧和出棧都在 q1 中完成,q2 只作為臨時中轉空間。
解題:
/**
* 5. 佇列實現棧
*/
class Myqueue {
constructor (){
this.items = []
}
enqueue (element){
this.items.push(element)
}
dequeue (){
return this.items.shift()
}
}
class Mystack {
constructor (){
this.q1 = new myQueue()
this.q2 = new myQueue()
}
push (element){
this.q1.enqueue(element)
this.q2.items = []
let len = this.q1.items.length
while(len > 0){
this.q2.enqueue(this.q1.items[len-1])
len --
}
}
pop (){
let result = this.q2.dequeue()
let len = this.q2.items.length
this.q1.items = []
while(len > 0){
this.q1.enqueue(this.q2.items[len-1])
len --
}
return result
}
print (){
console.log(this.q1.items.toString())
}
}
複製程式碼
這裡也可以直接使用第二題定義的Queue來實現:
class QueueStack {
constructor() {
this.queue = new Queue();
}
push(item) {
this.queue.enqueue(item);
}
pop() {
// 向佇列末尾追加 佇列長度-1 次,後彈出佇列頭部
for(let i = 1; i < this.queue.size(); i += 1) {
this.queue.enqueue(this.queue.dequeue());
}
return this.queue.dequeue();
}
peek() {
return this.queue.tail();
}
}
複製程式碼
下週預告
下週將練習集合(Set) 的題目,五一要到咯,也要好好做自己一個專案了。