1 / 38

データ構造とアルゴリズム

データ構造とアルゴリズム. 第 6 回 キュー ~ データ構造( 2 )~. スタック ユニークな回答と多かった回答. ユニーク 編 ・自分の家の冷蔵庫 ( 新しいものばかり食べています ) 。 ・ティッシュを間違って 2 枚取り出したとき使わなかった 1 枚は再び突っ込みます。次に使うときにはそれを使うのでスタックでしょうか。 ・小学校でよく使う上から入れてどんどんためていくファイル。 ・メジャー。. 多数編 ・箪笥の服 ・レポートの提出 ・銃 ( ハンドガン ) のマガジン ・食器 ・コピー機 の紙. キュー ユニークな回答と多かった回答.

renata
Download Presentation

データ構造とアルゴリズム

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. データ構造とアルゴリズム 第6回 キュー ~ データ構造(2)~

  2. スタック ユニークな回答と多かった回答 • ユニーク編 • ・自分の家の冷蔵庫(新しいものばかり食べています)。 • ・ティッシュを間違って2枚取り出したとき使わなかった1枚は再び突っ込みます。次に使うときにはそれを使うのでスタックでしょうか。 • ・小学校でよく使う上から入れてどんどんためていくファイル。 • ・メジャー。 • 多数編 • ・箪笥の服 • ・レポートの提出 • ・銃(ハンドガン)のマガジン • ・食器 • ・コピー機の紙

  3. キュー ユニークな回答と多かった回答 • ユニーク編 • ・学校:基本的に先に入った人から出ていく(卒業していく) • ・観覧車 • ・髪の毛:先に生えたところから切られるから • ・「便通」←食べたものは下から出る(笑) • 多数編 • ・自動販売機 • ・スーパー(コンビニを含む)商品の品だし • ・シャープペンシル • ・エスカレーター • ・行列

  4. キュー(待ち行列、Queue)

  5. 本日の内容:キュー • キュー • 抽象データ型としてのキュー • 単方向リストによるキューの実現 • 循環配列(リングバッファ)によるキューの実現 英国では行列することをqueueingという。 The verb queue means to form a line, and to wait for services. Queue is also the name of this line.

  6. 待ち行列 レジ A君の レポート B君の レポート C君の レポート

  7. キュー (Queue) • キュー:要素の挿入がいつも一方の端(末尾)からしかできず,要素の削除はその反対の端(先頭)からしかできないリスト • 先に入れた要素ほど,先に出る 別名 • 先入れ先出しリスト • FIFO (first-in first-out) 先頭 ↓ 末尾 ↓ a1 a2 a3 a4

  8. 抽象データ型としてのキュー • 抽象データ型: データ構造+操作 キュー 操作 要素の挿入 Enqueue, Enq 要素を 並べたもの 要素の取出し Dequeue, Deq

  9. キューの操作   • CREATE(Q ) • TOP(Q ) • ENQUEUE( x, Q ) ( Enq ( x, Q ) ) • DEQUEUE(Q ) ( Deq (Q ) )

  10. キューの操作 • Enq (x, Q ):要素xをキューQの末尾に入れる. • Deq (Q ):キューの先頭の要素を削除する <同時にSの先頭の要素を返す場合もある>

  11. 例  末尾 ↓ 先頭 ↓ Q 初期状態 Enq(A, Q) Enq(B, Q) Enq(C, Q) Deq(Q) Enq(Deq(Q), Q)

  12. 例  末尾 ↓ 先頭 ↓ Q 初期状態 A Enq(A, Q) Enq(B, Q) B A C B A Enq(C, Q) A B C Deq(Q) C B Enq(Deq(Q), Q)

  13. 単方向リストによるキューの実現 構造体 struct queue型 キューの先頭へのポインタ Queue型 front rear キューの末尾へのポインタ an-1 a0 a1 rear->element front->element キューの末尾要素 rear->nextはNULL キューの先頭要素

  14. キューの型定義とEnqueueのプログラム例(p38)キューの型定義とEnqueueのプログラム例(p38) /* セルを表わす構造体の定義 */ struct cell { int element; struct cell *next; }; … main() … struct queue { struct cell *front; struct cell *rear; } セルのデータ構造はリストのときと同じ。 ここではint型の要素としたが、どのような型でも良い。 先頭を指すfrontと末尾を指すrearの2つのポインタから成る構造体でキューを定義

  15. Enqのプログラム例(p38) … Main() { struct queue Q; Q.front =Q.rear =NULL; … } void enqueue(init x, struct queue *S) { struct cell *p; p=(struct cell *)malloc(sizeof(struct cell)); if(S ->rear != NULL) S ->rear->next = p; S ->rear = p; if(S ->front == NULL) S ->front = p; S ->rear->element = x; S ->rear->next = NULL; return; }

  16. Enqの実現(単方向リスト版) struct queue型の変数Q struct queue型を指すポインタ S • 初期状態 • front, rearともにNULL • 関数enqueueにおいて、仮引数Sは、struct queue 型を指すポインタ Q front rear struct queue Q; Q.front =Q.rear =NULL; 教科書では、両方とも Qなので混乱する。 スライドでは、ポインタをSとしておく … … void enqueue(init x, struct queue *S)

  17. Enqの実現(単方向リスト版) • Enq(x, Q) [void enqueue(int x, struct queue *S)] ① 新しいセル用のメモリを確保し, pはそのセルを指すポインタとする S Q an-1 a0 a1 front rear p ① p = (struct cell *)malloc(sizeof(struct cell));

  18. Enqの実現(単方向リスト版) • Enq(x, Q) [void enqueue(int x, struct queue *S)] ① 新しいセル用のメモリを確保し, pはそのセルを指すポインタとする ② Sが指しているキューQが空でなければ、 S->rear->nextが新しいセルを指す(pを代入) S ②if(S ->rear != NULL) S ->rear->next = p; Q an-1 a0 a1 front rear p

  19. Enqの実現(単方向リスト版) • Enq(x, Q) [void enqueue(int x, struct queue *S)] ① 新しいセル用のメモリを確保し, pはそのセルを指すポインタとする ② Sが指しているキューQが空でなければ、 S->rear->nextが新しいセルを指す(pを代入) ③ S->rearが新しいセルを指す(pを代入) S Q an-1 a0 a1 front rear ③ S ->rear = p; p

  20. Enqの実現(単方向リスト版) • Enq(x, Q) [void enqueue(int x, struct queue *Q)] ① 新しいセル用のメモリを確保し, pはそのセルを指すポインタとする ② Sが指しているキューQが空でなければ、 S->rear->nextが新しいセルを指す(pを代入) ③ S->rearが新しいセルを指す(pを代入) ④ Sが指しているキューQが空ならば、 S->frontが新しいセルを指す (pを代入) ④ if(S ->front == NULL) S ->front = p; S S p Q Q front front rear rear

  21. Enqの実現(単方向リスト版) • Enq(x, Q) [void enqueue(int x, struct queue *Q)] … ④ Sが指しているキューQが空ならば、 S->frontが新しいセルを指す(pを代入) ⑤新しいセルに要素xを代入 ⑥新しいセルは最後尾なので、そのnextはNULL S Q an-1 a0 a1 front rear ⑤ S ->rear->element = x; ⑥ S ->rear->next = NULL; x p

  22. Deqのプログラム例(p38) void dequeue(struct queue *S) { struct cell *q; if(S->front == NULL) { printf(“Error: Queue is empty. ¥n);exit(1); } else { q = S->front; S->front = S->front->next; free(q); } if(S->front == NULL) S->rear = NULL; return; }

  23. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] • Sが指すQのfront がNULLならキューが空  ① エラーメッセージを表示して関数を終了 S ① if(S->front == NULL) { printf(“Error: Queue is empty. ¥n); exit(1); } Q front rear

  24. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] … • キューQが空ではない場合は ② qにS->frontを代入する(=前の先頭要素へのポインタをqに保持しておく) S q ② q = S->front; an-1 a0 a1 front Q rear

  25. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] … • キューQが空ではない場合は ② qにS->frontを代入する(=前の先頭要素へのポインタをqに保持しておく)  ③ S->frontを前の先頭要素の次(=前の2番目)へのポインタとする S q an-1 a0 a1 front ③ S->front = S->front->next; Q rear

  26. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] … • キューQが空ではない場合は ② qにS->frontを代入する(=前の先頭要素へのポインタをqに保持しておく)  ③ S->frontを前の先頭要素の次(=前の2番目)へのポインタとする ④ 削除するセルの領域を解放 S q ④ free(q); an-1 a0 a1 front rear Q

  27. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] • キューQが要素1個だった場合は (= S->front がNULLの場合は)  ⑤ キューQは空とする(S->rearもNULLにする) ⑤ if(S->front == NULL) S->rear = NULL; q S S a0 front Q front Q rear rear

  28. Deqの実現(単方向リスト版) • Deq(Q)[void dequeue(struct queue *S)] ・いずれの場合も先頭要素が削除される ・教科書p38のプログラムはvoid関数なので、戻り値はなし 元のキューQが要素1個だった場合 元のキューQが要素2個以上だった場合 S S an-1 a1 front front Q rear Q rear

  29. p k 配列によるキューの実現 element [0] [1] データがある部分 a0 front [p] a1 an-1 rear [k] [N-1]

  30. キューの型の定義 (配列版) #define N 7 struct QUEUE/* 構造体queueの定義 */ { int element[N]; int front; int rear; }; 先頭と末尾の要素の位置を格納するためのメンバー

  31. p k+1 k p+1 配列によるキューの実現 element [0] • Deq frontが1つ下がる (キューの先頭の要素を返す場合もある) • Enq rearが1つ下がり,そこに新しいデータが入る [1] front a0 [p] a1 [p+1] rear an-1 [k] x [k+1] [N-1]

  32. rear 6 front 3 Enq,Deqを繰り返すとどうなるか? N=7の場合 element • Enq,Deqを繰り返していくと,データ部分は一方向に移動し,ついには,配列の端からはみ出してしまう ⇒これを防ぐ手法の一つが,循環配列 [0] [1] [2] [3] A [4] B [5] C [6] D

  33. rear an-1 a0 front … a1 循環配列(Ring Buffer) element[N-1] element[0]

  34. front front front 1 3 5 rear rear rear 4 6 1 循環配列(Ring Buffer) element element element [0] [0] [0] G [1] [1] [1] A H [2] [2] [2] B [3] [3] [3] C C [4] [4] [4] D D [5] [5] [5] E E [6] [6] [6] F F

  35. 循環配列の問題点 • このままでは,「キューがFULLの状態」と「キューが空の状態」の区別がつかない [0] キューがFULLの状態    ⇒rearの1つ後ろがfront 一見問題無いように思えるが… rear an-1 front a0 a1 [N-1]

  36. an-1 循環配列の問題点(続き) 要素1つの状態 ここからDeqを行うとキューは空になる キューが空の状態 frontとrearの関係が, キューがFULLの時と同じ! [0] [0] [1] [1] front rear rear Deq front [N-1] [N-1]

  37. 解決方法 • 「キューがFULLの状態」と「キューが空の状態」をどう区別するか? • 方法1: FULLの状態と空の状態を区別するためのフラグ(キューが空かどうかを表わす変数など)を用意する • 方法2: 待ち行列が配列いっぱいにならないようにする etc.

  38. 解決方法 方法2: 待ち行列が配列いっぱいにならないようにする例 この状態をFULLとする。 この状態を空とする。 [0] [0] rear rear an-1 front front a0 a1 [N-1] [N-1]

More Related