Queues from Scratch (Queue ကို အစကနေ ကိုယ်တိုင် တည်ဆောက်ခြင်း)

B4.1.1 (HL): Explain the properties and purpose of ADTs in programming. Implement a queue as an ADT using linked list nodes.
မြန်မာလို: programming မှာ ADT (abstract data type: operation တွေနဲ့ သတ်မှတ်တဲ့ ဒေတာ အမျိုးအစား) တွေရဲ့ ဂုဏ်သတ္တိတွေနဲ့ ရည်ရွယ်ချက်ကို ရှင်းပြနိုင်ရပါမယ်။ Linked list (node တွေ ချိတ်ဆက်ထားတဲ့ list) ရဲ့ node (ဒေတာ သိမ်းထားတဲ့ အကွက်) တွေကို သုံးပြီး queue (အရင်ထည့်တာ အရင်ထွက်တဲ့ တန်း) ကို ADT တစ်ခုအဖြစ် ကိုယ်တိုင် ရေးနိုင်ရပါမယ်။

ဒီစာမျက်နှာက HL အတွက်ပဲ ဖြစ်ပါတယ်။ SL (Standard Level) နဲ့ HL (Higher Level) ဆိုတာ IB Computer Science (နိုင်ငံတကာ ကျောင်းတွေမှာ သင်တဲ့ ကွန်ပျူတာသိပ္ပံ သင်ရိုး) သင်တန်းရဲ့ အဆင့်နှစ်ဆင့်ဖြစ်ပြီး HL အပိုင်းတွေက ပိုနက်နက်ရှိုင်းရှိုင်း လေ့လာရတဲ့ အပိုင်းတွေပါ။


အဓိက အယူအဆများ

Queues စာမျက်နှာမှာ Java ရဲ့ LinkedList class (object တွေ ဖန်တီးဖို့ ပုံစံခွက်) ကို queue အဖြစ် သုံးပြီး queue တွေကို သုံး တတ်အောင် လေ့လာခဲ့ပါတယ်။ ဒီစာမျက်နှာမှာတော့ queue တစ်ခုကို အစကနေ ကိုယ်တိုင် တည်ဆောက် မှာ ဖြစ်ပြီး enqueue (queue ရဲ့ နောက်ဆုံးမှာ ထည့်ခြင်း) နဲ့ dequeue (queue ရဲ့ ရှေ့ဆုံးကနေ ဖယ်ထုတ်ခြင်း) က node အဆင့်မှာ ဘယ်လို အလုပ်လုပ်လဲ နားလည်အောင် လေ့လာပါမယ်။

Queue ရဲ့ Operation များကို ပြန်နွှေးခြင်း

Queue က FIFO (First In, First Out: အရင်ဝင်တာ အရင်ထွက်) စည်းမျဉ်းအတိုင်း အလုပ်လုပ်ပါတယ်:

Operation (လုပ်ဆောင်ချက်) ဖော်ပြချက် ကြာချိန်
enqueue(item) item ကို နောက်ဆုံးမှာ ထည့်တယ် Tail (list ရဲ့ နောက်ဆုံး node) ကို မှတ်ထားရင် O(1) (ကြာချိန် ပုံသေ)
dequeue() ရှေ့ဆုံးက item (အချက်) ကို ဖယ်ထုတ်ပြီး ပြန်ပေးတယ် O(1)
peek() ရှေ့ဆုံးက item ကို မဖယ်ဘဲ ကြည့်တယ် O(1)
isEmpty() Queue ထဲမှာ element (အစုထဲက အချက်) တစ်ခုမှ မရှိဘူးလား စစ်တယ် O(1)
size() Element အရေအတွက်ကို ပြန်ပေးတယ် O(1)

Linked List ကို သုံးပြီး တည်ဆောက်မယ့် နည်းလမ်း

Queue က အစွန်း နှစ်ဖက်လုံး ကို မြန်မြန် ယူသုံးနိုင်ဖို့ လိုပါတယ်: နောက်ဆုံးမှာ enqueue လုပ်ပြီး ရှေ့ဆုံးကနေ dequeue လုပ်ပါတယ်။ ဒါကြောင့် reference (object ရှိရာ memory နေရာကို ညွှန်းတဲ့ တန်ဖိုး) နှစ်ခုကို ထိန်းထားပါတယ်:

  • front (head: list ရဲ့ ရှေ့ဆုံး node): item တွေကို dequeue လုပ်တဲ့ နေရာ
  • rear (tail): item တွေကို enqueue လုပ်တဲ့ နေရာ

ဒီလိုဆိုရင် operation နှစ်ခုလုံးက O(1) ဖြစ်ပြီး traversal (node ဒါမှမဟုတ် element တိုင်းကို အစဉ်တကျ သွားကြည့်ခြင်း) မလိုပါဘူး။

front က ပထမ node ဖြစ်တဲ့ Alice ကို ညွှန်းပါတယ်၊ dequeue က ဒီကနေ item တွေကို ဖယ်ထုတ်ပါတယ်။ rear က နောက်ဆုံး node ဖြစ်တဲ့ Carlos ကို ညွှန်းပါတယ်၊ enqueue က ဒီ node ရဲ့ နောက်မှာ item တွေကို ထည့်ပါတယ်။ Alice က Ben ကို ညွှန်းပါတယ်၊ Ben က Carlos ကို ညွှန်းပါတယ်၊ Carlos ရဲ့ next က null ပါ။ Alice Ben Carlos front rear null None dequeue here enqueue after here

ပုံထဲက English စာတွေရဲ့ အဓိပ္ပာယ်: “dequeue here” က ဒီကနေ dequeue လုပ်တယ်၊ “enqueue after here” က ဒီ node ရဲ့ နောက်မှာ enqueue လုပ်တယ်လို့ အဓိပ္ပာယ်ရပါတယ်။ ညာဘက် အစွန်းက null (ဘာ object ကိုမှ မညွှန်းတဲ့ တန်ဖိုး) က list ရဲ့ အဆုံးကို ပြပါတယ် (Python မှာ None ပါ)။

Stack နဲ့ Queue: Implementation (အထဲမှာ တကယ် အလုပ်လုပ်အောင် ရေးထားတဲ့ code) နှိုင်းယှဉ်ချက်

လက္ခဏာ LinkedStack LinkedQueue
ထိန်းထားတဲ့ reference များ top (head ပဲ) front (head) + rear (tail)
ထည့်ခြင်း Head မှာ (push: stack ရဲ့ အပေါ်ဆုံးမှာ ထည့်ခြင်း) Tail မှာ (enqueue)
ဖယ်ထုတ်ခြင်း Head ကနေ (pop: stack ရဲ့ အပေါ်ဆုံးကနေ ဖယ်ထုတ်ခြင်း) Head ကနေ (dequeue)
စည်းမျဉ်း LIFO (နောက်ဆုံးဝင်တာ အရင်ထွက်) FIFO
Node class အတူတူ အတူတူ

နှစ်ခုလုံးက Node class တစ်ခုတည်းကို သုံးပါတယ်။ တစ်ခုတည်းသော ကွာခြားချက်က item အသစ်တွေကို ဘယ်နေရာမှာ ထည့်လဲ ဆိုတာပါ: stack (အပေါ်ကနေပဲ ထည့်၊ ထုတ်တဲ့ အထပ်) က အစွန်း တစ်ဖက်တည်း (head) မှာ ထည့်ပြီး အဲဒီကနေပဲ ဖယ်ထုတ်ပါတယ်၊ queue ကတော့ အစွန်း တစ်ဖက် (tail) မှာ ထည့်ပြီး နောက်တစ်ဖက် (head) ကနေ ဖယ်ထုတ်ပါတယ်။


အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ

ဥပမာ 1: LinkedQueue ရဲ့ Implementation

public class LinkedQueue {
    private Node front;   // head -- dequeue from here
    private Node rear;    // tail -- enqueue here
    private int count;

    public LinkedQueue() {
        front = null;
        rear = null;
        count = 0;
    }

    // Enqueue: add to the back (tail)
    public void enqueue(String item) {
        Node newNode = new Node(item);
        if (rear == null) {
            // Empty queue: new node is both front and rear
            front = newNode;
            rear = newNode;
        } else {
            rear.next = newNode;   // link current rear to new node
            rear = newNode;        // update rear to new node
        }
        count++;
    }

    // Dequeue: remove and return from the front (head)
    public String dequeue() {
        if (front == null) {
            System.out.println("Queue is empty");
            return null;
        }
        String data = front.data;
        front = front.next;
        if (front == null) {
            rear = null;   // queue is now empty
        }
        count--;
        return data;
    }

    // Peek: view front without removing
    public String peek() {
        if (front == null) {
            System.out.println("Queue is empty");
            return null;
        }
        return front.data;
    }

    public boolean isEmpty() {
        return front == null;
    }

    public int size() {
        return count;
    }

    public void printQueue() {
        System.out.print("FRONT -> ");
        Node current = front;
        while (current != null) {
            System.out.print(current.data + " -> ");
            current = current.next;
        }
        System.out.println("null <- REAR");
    }

    public static void main(String[] args) {
        LinkedQueue queue = new LinkedQueue();
        queue.enqueue("Alice");
        queue.enqueue("Ben");
        queue.enqueue("Carlos");

        queue.printQueue();
        System.out.println("Peek: " + queue.peek());
        System.out.println("Size: " + queue.size());

        System.out.println("Dequeue: " + queue.dequeue());
        System.out.println("Dequeue: " + queue.dequeue());
        queue.printQueue();
        System.out.println("Size: " + queue.size());
    }
}
# The Node class from the Linked Lists page
class Node():
    def __init__(self, data):
        self.data = data    # the value this node stores
        self.next = None    # reference to the next node

class LinkedQueue():
    def __init__(self):
        self._front = None   # head -- dequeue from here
        self._rear = None    # tail -- enqueue here
        self._count = 0      # the leading underscore marks these as private (IB convention)

    # Enqueue: add to the back (tail)
    def enqueue(self, item):
        new_node = Node(item)
        if self._rear == None:
            # Empty queue: new node is both front and rear
            self._front = new_node
            self._rear = new_node
        else:
            self._rear.next = new_node   # link current rear to new node
            self._rear = new_node        # update rear to new node
        self._count = self._count + 1

    # Dequeue: remove and return from the front (head)
    def dequeue(self):
        if self._front == None:
            print("Queue is empty")
            return None
        data = self._front.data
        self._front = self._front.next
        if self._front == None:
            self._rear = None    # queue is now empty
        self._count = self._count - 1
        return data

    # Peek: view front without removing
    def peek(self):
        if self._front == None:
            print("Queue is empty")
            return None
        return self._front.data

    def isEmpty(self):
        return self._front == None

    def size(self):
        return self._count

    def print_queue(self):
        print("FRONT -> ", end="")
        current = self._front
        while current != None:
            print(current.data + " -> ", end="")
            current = current.next
        print("null <- REAR")

queue = LinkedQueue()
queue.enqueue("Alice")
queue.enqueue("Ben")
queue.enqueue("Carlos")

queue.print_queue()
print("Peek:", queue.peek())
print("Size:", queue.size())

print("Dequeue:", queue.dequeue())
print("Dequeue:", queue.dequeue())
queue.print_queue()
print("Size:", queue.size())

Output (program က ထုတ်ပြတဲ့ ရလဒ်):

FRONT -> Alice -> Ben -> Carlos -> null <- REAR
Peek: Alice
Size: 3
Dequeue: Alice
Dequeue: Ben
FRONT -> Carlos -> null <- REAR
Size: 1

FIFO အစဉ်ကို သတိပြုကြည့်ပါ: Alice ကို အရင်ဆုံး enqueue လုပ်ခဲ့လို့ အရင်ဆုံး dequeue ဖြစ်ပါတယ်။

enqueue("Carlos"): Carlos ကို သိမ်းထားတဲ့ node အသစ် တစ်ခုကို ဖန်တီးထားပါပြီ။ rear node ဖြစ်တဲ့ Ben ရဲ့ next က အခု အဲဒီ node အသစ်ကို ညွှန်းပါတယ်။ rear ကတော့ Ben ကိုပဲ ညွှန်းနေပါသေးတယ်။ Alice Ben Carlos null None rear newNode new_node front 1 rear.next = newNode; self._rear.next = new_node rear က အခု နောက်ဆုံး node အသစ် ဖြစ်တဲ့ Carlos ကို ညွှန်းပါတယ်။ Queue က Alice၊ Ben၊ Carlos ဖြစ်ပါတယ်။ Alice Ben Carlos null None rear front 2 rear = newNode; self._rear = new_node dequeue(): return လုပ်ဖို့ Alice ရဲ့ တန်ဖိုးကို သိမ်းထားပြီး front က Ben ဆီ ရွှေ့သွားပါတယ်။ Alice ကို ဘာကမှ မညွှန်းတော့ပါဘူး (မျဉ်းပြတ်နဲ့ ပြထားပါတယ်)။ Queue က Ben၊ Carlos ဖြစ်ပါတယ်။ Alice Ben Carlos null None rear returns Alice front 3 front = front.next; self._front = self._front.next

enqueue("Carlos") လုပ်ပြီး နောက်မှာ dequeue() လုပ်ပုံပါ။ အဆင့်တိုင်းမှာ အရောင် ထင်းထားတဲ့ မြှားက အဲဒီ line က ပြောင်းလိုက်တဲ့ reference ပါ။

ပုံထဲက “returns Alice” က Alice ကို ပြန်ပေးတယ်လို့ အဓိပ္ပာယ်ရပါတယ်။

dequeue မှာ အလွန် အရေးကြီးတဲ့ edge case (ပုံမှန် မဟုတ်တဲ့ အစွန်းရောက် အခြေအနေ)။ နောက်ဆုံး item ကို dequeue လုပ်လိုက်တဲ့အခါ front က null ဖြစ်သွားပါတယ်။ rear = null လို့လည်း သတ်မှတ်ပေးရပါမယ်။ မဟုတ်ရင် rear က ဖယ်ထုတ်ပြီးသား node ကို ညွှန်းနေဆဲ ဖြစ်ပြီး နောက်တစ်ခါ enqueue လုပ်တဲ့အခါ ဘာနဲ့မှ မချိတ်တော့တဲ့ node နဲ့ သွားချိတ်မိပါလိမ့်မယ်။

ဥပမာ 2: Print Queue ကို အတုယူ ပုံဖော်ခြင်း

လက်တွေ့ ဘဝက အသုံးချပုံ တစ်ခုပါ: document တွေကို ရောက်တဲ့ အစဉ်အတိုင်း print ထုတ်ပေးတဲ့ printer queue ကို simulate (အစစ်အမှန်လို အတုယူ ပုံဖော်) လုပ်တာပါ။

public class PrinterQueue {
    public static void main(String[] args) {
        LinkedQueue printQueue = new LinkedQueue();

        // Documents arrive
        printQueue.enqueue("Report.pdf");
        printQueue.enqueue("Invoice.docx");
        printQueue.enqueue("Photo.png");
        printQueue.enqueue("Slides.pptx");

        System.out.println("Print queue:");
        printQueue.printQueue();

        // Process documents in FIFO order
        while (!printQueue.isEmpty()) {
            String doc = printQueue.dequeue();
            System.out.println("Printing: " + doc);
        }

        System.out.println("Queue empty: " + printQueue.isEmpty());
    }
}
print_queue = LinkedQueue()

# Documents arrive
print_queue.enqueue("Report.pdf")
print_queue.enqueue("Invoice.docx")
print_queue.enqueue("Photo.png")
print_queue.enqueue("Slides.pptx")

print("Print queue:")
print_queue.print_queue()

# Process documents in FIFO order
while print_queue.isEmpty() == False:
    doc = print_queue.dequeue()
    print("Printing:", doc)

# Python prints True here -- Java prints true
print("Queue empty:", print_queue.isEmpty())

Output:

Print queue:
FRONT -> Report.pdf -> Invoice.docx -> Photo.png -> Slides.pptx -> null <- REAR
Printing: Report.pdf
Printing: Invoice.docx
Printing: Photo.png
Printing: Slides.pptx
Queue empty: true

ဥပမာ 3: Hot Potato ကစားနည်း (Round-Robin)

Queue ကို သုံးပြီး round-robin (အလှည့်ကျ အချိန်ပေးတဲ့ scheduling) လုပ်ဆောင်ပုံကို simulate လုပ်နိုင်ပါတယ်: ရှေ့ဆုံး item ကို dequeue လုပ်၊ အလုပ်လုပ်ပြီးရင် နောက်ဆုံးမှာ ပြန် enqueue လုပ်ပါတယ်။ Hot Potato (ကစားသူတွေက အာလူးကို အလှည့်ကျ လက်ဆင့်ကမ်းပြီး သတ်မှတ်ထားတဲ့ အကြိမ်ရေ ကမ်းပြီးတိုင်း အာလူး ကိုင်ထားရတဲ့သူ ထွက်ရတဲ့ ကစားနည်း) က ဒီလို ပုံစံ တစ်ခုပါ။

public static String hotPotato(String[] players, int passes) {
    LinkedQueue circle = new LinkedQueue();
    for (int i = 0; i < players.length; i++) {
        String player = players[i];
        circle.enqueue(player);
    }
    // for-each version: for (String player : players) { circle.enqueue(player); }

    while (circle.size() > 1) {
        // Pass the potato
        for (int i = 0; i < passes; i++) {
            circle.enqueue(circle.dequeue());  // move front to back
        }
        String eliminated = circle.dequeue();
        System.out.println(eliminated + " is eliminated");
    }
    return circle.dequeue();  // last player standing
}

// hotPotato(new String[]{"Aiko","Ben","Carlos","Diana","Eve"}, 3)
// Eliminations: Diana, Carlos, Eve, Ben
// Winner: Aiko
def hot_potato(players, passes):
    circle = LinkedQueue()
    for i in range(len(players)):
        player = players[i]
        circle.enqueue(player)
    # for-each version: for player in players:

    while circle.size() > 1:
        # Pass the potato
        for i in range(passes):
            circle.enqueue(circle.dequeue())    # move front to back
        eliminated = circle.dequeue()
        print(eliminated, "is eliminated")
    return circle.dequeue()    # last player standing

# hot_potato(["Aiko", "Ben", "Carlos", "Diana", "Eve"], 3)
# Eliminations: Diana, Carlos, Eve, Ben
# Winner: Aiko

Quick Check (အမြန် စစ်ဆေးမေးခွန်း)

Q1. Linked queue က reference ဘယ်နှစ်ခု ထိန်းထားသလဲ။

Q2. enqueue က item အသစ်ကို ဘယ်မှာ ထည့်သလဲ။

Q3. နောက်ဆုံး item ကို dequeue လုပ်တဲ့အခါ rear ကို null လို့ ဘာကြောင့် သတ်မှတ်ရသလဲ။

Q4. Linked stack နဲ့ linked queue ကြားက ဖွဲ့စည်းပုံ ဆိုင်ရာ အဓိက ကွာခြားချက်က ဘာလဲ။

Q5. Linked queue မှာ enqueue နဲ့ dequeue ရဲ့ time complexity (input ကြီးလာရင် ကြာချိန် တိုးပုံ) က ဘာလဲ။


Trace Exercise (code ကို တစ်ဆင့်ချင်း လိုက်ကြည့်ခြင်း)

Operation တစ်ခုစီ ပြီးတိုင်း queue ရဲ့ အခြေအနေကို trace (တစ်ဆင့်ချင်း လိုက်ပြီး မှတ်) လုပ်ပါ။

LinkedQueue q = new LinkedQueue();
q.enqueue("X");
q.enqueue("Y");
q.enqueue("Z");
q.dequeue();
q.enqueue("W");
q.dequeue();
q = LinkedQueue()
q.enqueue("X")
q.enqueue("Y")
q.enqueue("Z")
q.dequeue()
q.enqueue("W")
q.dequeue()
လုပ်ပြီးတဲ့ operationfront (peek)rearQueue (front ကနေ rear)size()
enqueue("X") X 1
enqueue("Y") X 2
enqueue("Z") X X, Y, Z
dequeue() က X ကို ပြန်ပေး Z 2
enqueue("W") Y Y, Z, W 3
dequeue() က Y ကို ပြန်ပေး W

Code Completion (code ကွက်လပ် ဖြည့်ခြင်း)

Linked queue အတွက် enqueue method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) ကို ပြီးအောင် ဖြည့်ပါ။

Queue ရဲ့ rear မှာ item တစ်ခု ထည့်ဖို့ ကွက်လပ်တွေကို ဖြည့်ပါ:

public void enqueue(String item) {
    Node newNode = new Node(item);
    if (rear == null) {
        front = newNode;
         = newNode;
    } else {
        rear. = newNode;
        rear = ;
    }
    count++;
}

dequeue method ကို ပြီးအောင် ဖြည့်ပါ။

Front item ကို ဖယ်ထုတ်ပြီး ပြန်ပေးဖို့ ကွက်လပ်တွေကို ဖြည့်ပါ:

public String dequeue() {
    if (front == null) {
        return null;
    }
    String data = front.;
    front = front.;
    if (front == null) {
         = null;
    }
    count--;
    return data;
}

Spot the Error (အမှား ရှာခြင်း)

ဒီ queue က item အများကြီး ရှိနေတုန်းမှာ အလုပ်လုပ်ပေမယ့် နောက်ဆုံး item ကို dequeue လုပ်ပြီး နောက် ပြန် enqueue လုပ်တဲ့အခါ ပျက်သွားပါတယ်:

1public String dequeue() { 2 if (front == null) { 3 return null; 4 } 5 String data = front.data; 6 front = front.next; 7 count--; 8 return data; 9}

မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:


ဒီ queue က dequeue လုပ်တိုင်း နောက်ဆုံး ထည့်ခဲ့တဲ့ item ကို အမြဲ ပြန်ပေးနေပါတယ် (FIFO အစား LIFO ဖြစ်နေပါတယ်):

1public void enqueue(String item) { 2 Node newNode = new Node(item); 3 if (rear != null) { 4 rear.next = newNode; 5 } 6 front = newNode; 7 rear = newNode; 8 count++; 9}

Line 6 အတွက် မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:


Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)

ဒီ code က ဘာကို print ထုတ်မလဲ။

LinkedQueue q = new LinkedQueue();
q.enqueue("1");
q.enqueue("2");
q.enqueue("3");
System.out.println(q.dequeue());
q.enqueue("4");
System.out.println(q.peek());
System.out.println(q.dequeue());
System.out.println(q.size());

Output ကို အတိအကျ ရိုက်ထည့်ပါ:


ဒီ code က ဘာကို print ထုတ်မလဲ။

LinkedQueue q = new LinkedQueue();
q.enqueue("A");
q.enqueue("B");
q.enqueue("C");
while (!q.isEmpty()) {
    System.out.println(q.dequeue());
}
System.out.println(q.isEmpty());

Output ကို အတိအကျ ရိုက်ထည့်ပါ:


Practice Exercises (လေ့ကျင့်ခန်းများ)

Core (အခြေခံ အဆင့်)

  1. တည်ဆောက်ပြီး အလုပ်လုပ်ခိုင်းခြင်း: LinkedQueue တစ်ခု ဖန်တီးပါ၊ ဝယ်သူ နာမည် 5 ခုကို enqueue လုပ်ပါ၊ ပြီးရင် တစ်ခုချင်း dequeue လုပ်ပြီး print ထုတ်ပါ။ FIFO အစဉ်အတိုင်း ထွက်လာလား စစ်ပါ။
  2. ဗလာ queue မှာ ဘေးကင်းမှု: Item 2 ခုကို enqueue လုပ်ပါ၊ item 2 ခုကို dequeue လုပ်ပါ၊ ပြီးရင် နောက်တစ်ခါ dequeue လုပ်ကြည့်ပါ။ dequeue() က null ကို ပြန်ပေးပြီး isEmpty() က true ကို ပြန်ပေးလား စစ်ပါ။ ပြီးရင် item အသစ် တစ်ခုကို enqueue လုပ်ပြီး queue က ပြန် မှန်မှန်ကန်ကန် အလုပ်လုပ်လား စစ်ပါ။
  3. java.util.LinkedList နဲ့ နှိုင်းယှဉ်ခြင်း: ကိုယ့် LinkedQueue နဲ့ java.util.LinkedList<String> (add နဲ့ poll ကို သုံးပြီး) နှစ်ခုလုံးပေါ်မှာ operation 10 ခု အတူတူ လုပ်ပါ။ ရလဒ်တွေ အတူတူ ဖြစ်လား စစ်ပါ။

Extension (တိုးချဲ့ အဆင့်)

  1. Array ကို အခြေခံတဲ့ queue: ပုံသေ capacity (သိမ်းနိုင်တဲ့ အများဆုံး ပမာဏ) ရှိတဲ့ String[] array (အရွယ်အစား ပုံသေ၊ အမျိုးအစားတူ ဒေတာစု) ကို သုံးပြီး queue တစ်ခု ရေးပါ။ front နဲ့ rear index (နေရာအမှတ်) တွေက modulo (စားလို့ ကျန်တဲ့ အကြွင်းကို ရှာတဲ့ %) ကို သုံးပြီး array ရဲ့ အဆုံးရောက်ရင် အစကို ပြန်လှည့်လာတဲ့ circular (စက်ဝိုင်းပုံ) နည်းကို သုံးပါ။ Linked ပုံစံနဲ့ နှိုင်းယှဉ်ပါ။
  2. Task scheduler (အလုပ်တွေကို အလှည့်ကျ စီစဉ်ပေးတဲ့ program): ရိုးရှင်းတဲ့ round-robin task scheduler တစ်ခု တည်ဆောက်ပါ။ Task (အလုပ်) 4 ခုကို enqueue လုပ်ပါ။ အလှည့်တိုင်းမှာ task တစ်ခုကို dequeue လုပ်ပါ၊ “execute” လုပ်ပါ (သူ့ နာမည်ကို print ထုတ်ပါ)၊ task က မပြီးသေးရင် (ကျန်တဲ့ အချိန်ကို မှတ်ထားပါ) ပြန် enqueue လုပ်ပါ။ Task တစ်ခုစီက အချိန် ယူနစ် 3 ခုနဲ့ စပြီး အလှည့် တစ်ခါမှာ 1 ခု လျော့ပါတယ်။

Challenge (စိန်ခေါ်မှု အဆင့်)

  1. Priority queue (ဦးစားပေး အဆင့် မြင့်တာ အရင်ထွက်တဲ့ queue): Item တစ်ခုစီမှာ integer (ကိန်းပြည့်) priority (ဦးစားပေး အဆင့်) တစ်ခု ပါအောင် LinkedQueue ကို ပြင်ပါ။ enqueue က item ကို priority ပေါ် မူတည်ပြီး မှန်ကန်တဲ့ နေရာမှာ ထည့်ပါတယ် (priority မြင့်လေ front နဲ့ နီးလေ)။ dequeue ကတော့ front ကနေပဲ ဆက် ဖယ်ထုတ်ပါတယ်။ Priority အမျိုးမျိုး ရှိတဲ့ task တွေနဲ့ စမ်းပါ။
  2. Queue နှစ်ခုနဲ့ stack တည်ဆောက်ခြင်း: LinkedQueue instance (class တစ်ခုကနေ ဖန်တီးထားတဲ့ object) နှစ်ခုကိုပဲ သုံးပြီး stack တစ်ခု ရေးပါ (array တွေ ဒါမှမဟုတ် linked list တွေကို တိုက်ရိုက် မသုံးရပါ)။ Push နဲ့ pop က LIFO အစဉ်ကို ထိန်းထားရပါမယ်။ အကြံပြုချက်: push လုပ်တိုင်း ဗလာ queue ထဲကို enqueue လုပ်ပါ၊ ပြီးရင် နောက် queue ထဲက item အားလုံးကို ဒီ queue ထဲကို ရွှေ့ပါ။

ဆက်စပ် ခေါင်းစဉ်များ

  • အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Linked Lists: Node class နဲ့ အခြေခံ operation တွေ
  • အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Queues: Queue ADT ကို သုံးခြင်း (B2.2.4)
  • အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Stacks from Scratch (Stack ကို အစကနေ ကိုယ်တိုင် တည်ဆောက်ခြင်း): LIFO နဲ့ အလုပ်လုပ်တဲ့ အတွဲဖက်ပါ၊ သူ့ကိုလည်း node တွေနဲ့ တည်ဆောက်ပါတယ်
  • နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: Binary Search Trees (ဘယ်ဘက် ငယ်၊ ညာဘက် ကြီးတဲ့ binary tree များ): O(log n) နဲ့ ရှာနိုင်တဲ့ hierarchical (အထက်အောက် အဆင့်ဆင့် ဖွဲ့ထားတဲ့) data structure (ဒေတာ သိမ်းဆည်းပုံ)