《圖說演算法-使用C#》要點摘錄 – 「棧與隊列」
書名:《圖說演算法-使用C#》
作者:吳燦銘、胡昭民
所讀版本:博碩文化
數組實作Stack
-
public class ArrayStack { int[] stack; int top; //頂端索引 public ArrayStack(int size) { stack = new int[size]; top = -1; //實例化後默認頂端索引為-1(無元素) } public bool Push(int data) { if (top >= stack.Length) { return false; } //判斷Stack是否已經滿了 stack[++top] = data;//索引+1,把數據入堆 return true; } public bool IsEmpty() { return top == -1; } public int Pop() { if (IsEmpty()) { return -1; } //判斷Stack是否為空 return stack[top--]; //把數據出堆,索引-1 } }
鏈表實作Stack
-
public class LinkedListStack { public Node front; //指向堆的底端 public Node rear; //指向堆的頂端 public bool IsEmpty() { return front == null; } public void OutputStack() { Node curr = front; while(curr != null) { Console.Write(curr.val + " "); curr = curr.next; } Console.WriteLine(); } public void Push(int data) { Node newNode = new Node(data); if (IsEmpty()) { front = newNode; rear = newNode; } else { rear.next = newNode; rear = newNode; } } public void Pop() { Node target; if (IsEmpty()) { return; } target = front; if(target == rear) //只有一個元素 { front = null; rear = null; } else { while(target.next != rear) { target = target.next; } target.next = rear.next; rear = target; } } }
河內塔算法
- 假設有A, B, C三個木樁和n個大小不一的套環,由小到大的編號為1~n,編號越大,直徑越大。開始的時候,n個套環套在A木樁上。
- 直徑較小的套環永遠置於直徑較大的套環上。
- 套環可任意地由任何一個木樁移到其他的木樁上。
- 每一次僅能移動一個套環,而且只能從最上面的套環開始移動。
- 當有n個盤子時,河內塔的移動步驟
- 將n - 1個盤子從木樁1移動到木樁2
- 將n個最大盤子,從木樁1移動到木樁3
- 將n-1 個盤子,從木樁2移動到木樁3
public static void Hanoi(int n, int p1, int p2, int p3)
{
if(n == 1)
{
Console.WriteLine($"Plate Moved From {p1} To {p3}");
}
else
{
Hanoi(n - 1, p1, p3, p2);
Console.WriteLine($"Plate Moved From {p1} To {p3}");
Hanoi(n - 1, p2, p1, p3);
}
}
八皇后算法
- 在一個8*8棋盤內,置入一個皇后,確保這個位置不會被先前放置的皇后吃掉(直、橫、斜沒有其他皇后),就將這個皇后存入Stack。
- 當放置新皇后的該行的8個位置都沒有辦法放置新皇后,就從Stack取出上一個皇后的位置,並在那行找一個新的位置放置皇后,然後再將該位置存入Stack中(BackTracking)。
-
static int solutionCnt = 0; public static int TotalQueens() { int[,] chessBoard = new int[8, 8]; BackTrack(chessBoard, 0); return solutionCnt; } static void BackTrack(int[,] chessBoard, int currRow) { //Loop Column of chessBoard for (int col = 0; col < 8; col++) { if (chessBoard[currRow, col] == 0) //Placable { chessBoard[currRow, col] = 1; //Place Queen SetAttackRange(chessBoard, currRow, col, 1); //Set Attack Range if(currRow + 1 == 8) { //Current Combination Confirmed solutionCnt++; } else { //Move To Next Row BackTrack(chessBoard, currRow + 1); } //Remove Queen chessBoard[currRow, col] = 0; SetAttackRange(chessBoard, currRow, col, -1); } } } //標記攻撃範圍 static void SetAttackRange(int[,] chessBoard, int row, int col, int change) { //縱橫 for (int i = 0; i < 8; i++) { if (i != col) { chessBoard[row, i] += change; } if (i != row) { chessBoard[i, col] += change; } } //斜 //Top Left int y = row - 1; int x = col - 1; while (y >= 0 && x >= 0) { chessBoard[y--, x--] += change; } //Top Right y = row - 1; x = col + 1; while (y >= 0 && x < 8) { chessBoard[y--, x++] += change; } //Bottom Left y = row + 1; x = col - 1; while(y < 8 && x >= 0) { chessBoard[y++, x--] += change;} //Bottom Right y = row + 1; x = col + 1; while(y < 8 && x < 8) { chessBoard[y++, x++] += change; } }
數組實作Queue
-
public class ArrayQueue { int[] queue; int front; int rear; public ArrayQueue(int size) { queue = new int[size]; front = -1; rear = -1; } public bool Enqueue(int data) { if(rear + 1 == queue.Length) { return false; } queue[++rear] = data; return true; } public int Dequeue() { if(rear > front) { front++; int output = queue[front]; queue[front] = 0; return output; } return -1; } }
鏈表實作Queue
-
public class LinkedListQueue { public Node front; public Node rear; public LinkedListQueue() { front = null; rear = null; } public bool Enqueue(int data) { Node newNode = new Node(data); if(front == null) { front = newNode; } else { rear.next = newNode; } rear = newNode; return true; } public int Dequeue() { if (front == null) { return -1; } int value = front.val; if (front == rear) { rear = null; } front = front.next; return value; } }
雙向Queue
-
前後兩端都可以輸入/取出
-
加入及取出時,指標往Queue的中央移動
-
public class DoublyLinkedListQueue { public Node front; public Node rear; public DoublyLinkedListQueue() { front = null; rear = null; } //Only Insert Front Head public bool Enqueue(int data) { Node newNode = new Node(data); if(rear == null) { front = newNode; } else { rear.next = newNode; } rear = newNode; return true; } //Dequeue From Both Sides public int Dequeue(bool isFront) { int value; Node tmp; Node start; if(front != null && isFront) { value = front.val; front = front.next; return value; } else if(rear != null && !isFront) { start = front; //save ref of front; value = rear.val; tmp = front; //track to the node before rear node while(front.next != rear && front.next != null) { front = front.next; tmp = front; } front = start; //set new rear rear = tmp; //Dequeue Last Node if(front.next == null || rear.next == null) { front = null; rear = null; } return value; } else { return -1; } } }
優先Queue
- HPOF(Highest Priority Out First)rather than FIFO
- 為每一個元素賦予優先權,加入元素時任意加入,最高優先權者最先輸出