一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して8日目です。クリックしてイベントの詳細をご覧ください。
みなさん、こんにちは。私の名前はヤン・チェンゴンです。
前回の記事では、新しいデータ構造であるキューについて学びました。誰もがキューの「先入れ先出し」の原則を理解する必要があります。この記事では、両端キューと呼ばれる特別な種類のキューについて学習します。
それでもキューが何であるかわからない場合は、前の記事「AngryLivesJavaScriptデータ構造-キュー」をお読みください。
両端キューとは何ですか
キューの概念を最初に見てください。キューは、先入れ先出し(FIFO )の原則に従う順序付けられたコレクションのセットです。キューのルールは、末尾に新しい要素を追加し、先頭から最も近い要素を削除することです。
キューイングの例も示しました。たとえば、朝食を買いに行って前の人に会う場合は、後ろから列に並ぶ必要があります。前の人が最初に朝食を購入し、次に次の人が向きを変えることができます。
しかし、考えてみてください。そのようなシナリオはありますか。
- 私は列の後ろにいて、突然緊急事態が発生したので、私はすぐに出発しなければなりませんでした
- お金を払って帰ったところ、突然ストローがないことに気づいたので、前に走ってストローを手に入れました。
キューの観点からは、これら2つの状況は、「先入れ先出し」の原則に違反します。これは、最後にキューに入れられた新しい要素が実際にはキューの最後からデキューされたためです。実際にデキューされました。キューの先頭からエンキューされました。これは、キュー内のスタックの「後入れ先出し」の状況に相当します。
実際、これは両端キューであり、両端キューはキューます。
次に、特定の概念を見てみましょう。両端キュー、英語名dequeは、ヘッドとテールの要素を同時に追加および削除できる特別なキューです。キューとスタックを組み合わせたデータ構造と考えてください。
コンピュータの世界でdequesの最も一般的なアプリケーションは、undoです。たとえば、テキスト編集を行っている場合、各操作は両端キューに記録されます。通常の状況では、入力したテキストはこのキューの最後から継続的に挿入されます。最大1000語などの特定の条件が満たされた場合、キューの先頭から最初のテキストを削除できます。
しかし、突然、単語が間違って書かれていることに気づきました。このとき、キーボードでctrl+z
undoこのundo操作は、キューの最後から最後の単語をデキューして、単語が削除されたことを示します。
コンピューターと実際の両端キューはどちらも、「先入れ先出し」と「後入れ先出し」の原則に従います。
両端キューの実装
以前の知識を組み合わせて、JavaScriptオブジェクトに基づく両端キューを実装します。
const Deque = (()=> {
let _start;
let _end;
let _items;
class Deque {
constructor() {
_start = 0;
_end = 0;
_items = 0;
}
}
return Deque
})()
复制代码
上記のコードと同様に、items
属性は両端キューの要素を格納するために使用されます。これは、前のキューとまったく同じです。
両端キューもキューであるため、、などのキューの基本的な方法はisEmpty
、前のキューで説明したものclear
とまったく同じであるため、詳細については説明しません。知る必要がある人は、記事の冒頭にあるリンクをクリックしてください。 size
toString
通常のキューと比較すると、両端キューには次の方法があります。
addFront()
:両端キューの先頭から要素を追加しますaddBack()
:両端キューの最後から要素を追加します(キューのenqueueメソッドと同じ)removeFront()
:dequeの先頭から要素を削除します(キューのdequeueメソッドと同じ)removeBack()
:両端キューの最後から要素を削除します(スタックのpopメソッドと同じ)peekFront()
:両端キューの最初の要素を返します(キューのpeekメソッドと同じ)peekBack()
:両端キューの最後の要素を返します(スタックのpeekメソッドと同じ)
これらのメソッドのみaddFront()
が両端キューに固有であり、他のメソッドはスタックおよびキューの実装にあります。それでは、このユニークなメソッドがどのように実装されているかを見てみましょう。
addFront(item) {
if(this.isEmpty()) {
return this.addBack(item)
}
if(_start>0) {
_start--;
_items[_start] = item
} else {
for(let i = 0; i<_end; i++) {
_items[i+1] = _items[i]
}
_end++;
_start = 0;
_items[0] = item
}
}
复制代码
上記のコードは、両端キューの先頭にキューイングを実装します。これは3つのケースに分けられます。
ケース1:キューが空です
キューが空の場合、キューの先頭と末尾からの要素の挿入は同じです。したがって、この場合、要素を最後から挿入するメソッドを直接呼び出すことができます。
ケース2:開始の値が0より大きい
startの値が0より大きい場合は、dequeがすでにデキューされていることを意味します。この場合、新しく追加された要素を最後のデキューされた要素の位置に配置するだけで済みます。この位置のキー値は時間start - 1
です。
ケース3:startの値が0に等しい
startの値が0の場合、dequeでデキューされる要素がないことを意味します。このとき、ヘッドに新しい要素を追加するには、キュー内のすべての要素のキー値を1ビット後方、つまり+1に移動します。新しい要素のキー値を0とします。
スタックとキューの記事で他のメソッドが導入されました。完全なコードは次のとおりです。
const Deque = (() => {
let _start
let _end
let _items
class Deque {
constructor() {
_start = 0
_end = 0
_items = 0
}
// 头部入列
addFront(item) {
if (this.isEmpty()) {
return this.addBack(item)
}
if (_start > 0) {
_start--
_items[_start] = item
} else {
for (let i = 0; i < _end; i++) {
_items[i + 1] = _items[i]
}
_end++
_start = 0
_items[0] = item
}
}
// 尾部入列
addBack(item) {
_items[_end] = item
_end++;
}
// 头部出列
removeFront() {
if (this.isEmpty()) {
return undefind
}
let item = _items[_start]
delete _items[_start]
_start++;
return item
}
// 尾部出列
removeBack() {
if (this.isEmpty()) {
return undefined
}
_end--;
let item = _items[_end]
delete _items[_end]
return item
}
// 头部第一个元素
peekFront() {
if (this.isEmpty()) {
return undefined
}
return _items[_start]
}
// 尾部第一个元素
peekBack() {
if (this.isEmpty()) {
return undefined
}
return _items[_end]
}
size() {
return _end - _start
}
isEmpty() {
return _end - _start === 0
}
clear() {
_items = {}
_start = 0
_end = 0
}
toString() {
let arr = Object.values(_items)
return arr.toString()
}
}
return Deque
})()
复制代码
dequeを使用する
以前の完全なコードは比較的長いので、最初に試してみましょう。
// 实例化
var deque = new Deque();
console.log(deque.isEmpty()); // true
复制代码
まず、頭をエンキューした結果を試してください。
deque.addFront("北京");
deque.addFront("上海");
console.log(deque.size()); // 2
console.log(deque.toString()); // 上海,北京
复制代码
印刷結果を見るのに問題はありません。最後にもう一度列を入力してみましょう。
deque.addBack("杭州");
deque.addBack("南京");
console.log(deque.size()); // 4
console.log(deque.toString()); // 上海,北京,杭州,南京
复制代码
テールエントリも期待どおりであり、最後にデキューを確認します。
// 头部出列
console.log(deque.removeFront()); // 上海
// 尾部出列
console.log(deque.removeBack()); // 南京
console.log(deque.size()); // 2
console.log(deque.toString()); // 北京,杭州
复制代码
うーん、すべてが完璧に行われます。
要約する
この記事では、両端キューの概念を紹介し、両端キューを手動で実装します。あなたがまだそれを学んだかどうかわかりませんか?理解できない方法を見つけた場合は、列をクリックして、データ構造シリーズの以前の記事を表示してください。
この記事の出典は公式アカウントです:ProgrammerSuccess。これは、JavaScriptのデータ構造とアルゴリズムの学習の第7部です。このシリーズは1か月間更新されます。公式アカウントに注目し、[グループの追加]をクリックして学習チームに参加してください。