วิธีการใช้คิวโดยใช้สองกอง


394

สมมติว่าเรามีสองกองและไม่มีตัวแปรชั่วคราวอื่น ๆ

เป็นไปได้ที่จะ "สร้าง" โครงสร้างข้อมูลคิวโดยใช้ทั้งสองกองเท่านั้นหรือไม่

คำตอบ:


701

เก็บ 2 กองขอเรียกพวกเขาและinboxoutbox

เข้าคิว :

  • ผลักองค์ประกอบใหม่เข้าสู่ inbox

Dequeue :

  • หากoutboxไม่มีข้อมูลให้เติมโดยการเปิดแต่ละองค์ประกอบจากinboxนั้นกดลงoutbox

  • ป๊อปและกลับองค์ประกอบยอดนิยมจาก outbox

การใช้วิธีนี้แต่ละองค์ประกอบจะอยู่ในแต่ละสแต็คหนึ่งครั้ง - หมายถึงแต่ละองค์ประกอบจะถูกผลักสองครั้งและผุดสองครั้งทำให้มีการดำเนินการเวลาคงที่ที่ถูกตัดจำหน่าย

นี่คือการใช้งานใน Java:

public class Queue<E>
{

    private Stack<E> inbox = new Stack<E>();
    private Stack<E> outbox = new Stack<E>();

    public void queue(E item) {
        inbox.push(item);
    }

    public E dequeue() {
        if (outbox.isEmpty()) {
            while (!inbox.isEmpty()) {
               outbox.push(inbox.pop());
            }
        }
        return outbox.pop();
    }

}

13
ความซับซ้อนของเวลาที่เลวร้ายที่สุดยังคงเป็น O (n) ฉันยังคงพูดอย่างนี้อยู่เพราะฉันหวังว่าจะไม่มีนักเรียนอยู่ที่นั่น (ฟังดูเหมือนการบ้าน / คำถามทางการศึกษา) คิดว่านี่เป็นวิธีที่ยอมรับได้ในการใช้คิว
Tyler

26
มันเป็นความจริงที่ว่าเวลาที่เลวร้ายที่สุดสำหรับการดำเนินการ pop เดียวคือ O (n) (โดยที่ n คือขนาดปัจจุบันของคิว) อย่างไรก็ตามเวลาที่เลวร้ายที่สุดสำหรับลำดับของการดำเนินการคิว n ยังเป็น O (n) ทำให้เรามีเวลาคงที่ตัดจำหน่าย ฉันจะไม่ใช้คิวในลักษณะนี้ แต่ก็ไม่ได้แย่ขนาดนั้น
Dave L.

1
@Tyler หากสแต็กของคุณเรียงตามอาเรย์ส่วนใหญ่คุณจะได้รับ O (n) เคสที่แย่ที่สุดสำหรับการดำเนินการครั้งเดียว
โทมัส Ahle

2
@Tyler: ตรวจสอบsgi.com/tech/stl/Deque.html Deque "สร้างการเข้าถึงองค์ประกอบแบบสุ่มโดยอัตโนมัติ" ดังนั้นทั้ง deque และ stack จึงเป็นไปตามอาเรย์ นี่เป็นเพราะช่วยให้คุณสามารถอ้างอิงได้ดีขึ้นและเร็วขึ้นในทางปฏิบัติ
โทมัส Ahle

13
@Newtang ก) คิว 1,2,3 => Inbox [3,2,1] / กล่องขาออก [] b) การถอนออก ขาออกเป็นที่ว่างเปล่าเพื่อเติมเงิน => Inbox [] / กล่องขาออก [1,2,3] ป๊อปจากกล่องขาออกกลับ 1 => Inbox [] / กล่องขาออก [2,3] c) คิว 4,5 => Inbox [5,4] / กล่องขาออก [2,3] d) ถอนออก ขาออกไม่ว่างเปล่าดังนั้น pop จากขาออกกลับ 2 => Inbox [5,4] / กล่องขาออก [3] นั่นทำให้รู้สึกมากขึ้น?
Dave L.

226

เอ - วิธีการย้อนกลับกอง

เพื่อให้เข้าใจถึงวิธีการสร้างคิวโดยใช้สองสแต็คคุณควรเข้าใจวิธีการกลับสแต็คคริสตัลที่ชัดเจน โปรดจำไว้ว่าการทำงานของสแต็กคล้ายกับจานสแต็คในครัวของคุณมาก จานล้างสุดท้ายจะอยู่ด้านบนของกองสะอาดซึ่งเรียกว่าเป็นL ast I n F irst O ut (LIFO) ในวิทยาศาสตร์คอมพิวเตอร์

ให้จินตนาการว่ากองของเราเหมือนขวดดังต่อไปนี้

ป้อนคำอธิบายรูปภาพที่นี่

หากเรากดจำนวนเต็ม 1,2,3 ตามลำดับแล้ว 3 จะอยู่ด้านบนสุดของสแต็ก เนื่องจาก 1 จะถูกผลักก่อนจากนั้นจะวาง 2 ที่ด้านบนของ 1 สุดท้าย 3 จะวางที่ด้านบนสุดของสแต็คและสถานะล่าสุดของสแต็กของเราที่แสดงเป็นขวดจะเป็นด้านล่าง

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้เรามีสแต็กของเราแสดงเป็นขวดที่บรรจุด้วยค่า 3,2,1 และเราต้องการย้อนกลับสแต็คเพื่อให้องค์ประกอบด้านบนของสแต็กจะเป็น 1 และองค์ประกอบด้านล่างของสแต็กจะเป็น 3 เราจะทำอย่างไร เราสามารถนำขวดไปวางไว้คว่ำเพื่อให้ค่าทั้งหมดควรย้อนกลับตามลำดับ

ป้อนคำอธิบายรูปภาพที่นี่

ใช่เราทำได้ แต่นั่นคือขวด ในการทำกระบวนการเดียวกันเราต้องมีสแต็กที่สองซึ่งจะเก็บองค์ประกอบสแต็กแรกในลำดับย้อนกลับ ลองใส่สแต็คที่มีประชากรของเราไปทางซ้ายและสแต็กเปล่าใหม่ของเราไปทางขวา ในการย้อนกลับลำดับขององค์ประกอบเราจะป๊อปแต่ละองค์ประกอบจากสแต็กซ้ายและผลักไปที่สแต็กขวา คุณสามารถเห็นสิ่งที่เกิดขึ้นในขณะที่เราทำในภาพด้านล่าง;

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นเราจึงรู้วิธีย้อนกลับกองซ้อน

B - การใช้สองกองเป็นคิว

ในส่วนก่อนหน้านี้ฉันได้อธิบายวิธีที่เราสามารถย้อนกลับลำดับขององค์ประกอบสแต็ค นี่เป็นสิ่งสำคัญเพราะถ้าเรากดและองค์ประกอบป๊อปอัพไปยังสแต็คผลลัพธ์จะอยู่ในลำดับที่แน่นอนของคิว ลองนึกถึงตัวอย่างลองผลักอาร์เรย์จำนวนเต็ม{1, 2, 3, 4, 5}ไปที่สแต็ก หากเราปรากฏองค์ประกอบและพิมพ์จนกว่าสแต็กจะว่างเปล่าเราจะได้รับอาเรย์ในลำดับย้อนกลับของการผลักดันคำสั่งซึ่งจะ{5, 4, 3, 2, 1}จำไว้ว่าสำหรับการป้อนข้อมูลเดียวกันถ้าเรา dequeue คิวจนกว่าคิวจะว่างเปล่าเอาท์พุท {1, 2, 3, 4, 5}จะเป็น ดังนั้นจึงเห็นได้ชัดว่าสำหรับลำดับขององค์ประกอบอินพุตเดียวกันเอาต์พุตของคิวนั้นตรงกันข้ามกับเอาต์พุตของสแต็ก เมื่อเรารู้วิธีย้อนกลับสแต็กโดยใช้สแต็กพิเศษเราสามารถสร้างคิวโดยใช้สองสแต็ค

แบบจำลองคิวของเราจะประกอบด้วยสองกอง สแต็กหนึ่งจะใช้สำหรับenqueueการดำเนินการ (สแต็ค # 1 ทางด้านซ้ายจะถูกเรียกว่าอินพุตสแต็ก) สแต็กอื่นจะถูกใช้สำหรับการdequeueดำเนินการ (สแต็ก # 2 ทางด้านขวาจะถูกเรียกว่าเป็น ตรวจสอบภาพด้านล่าง;

ป้อนคำอธิบายรูปภาพที่นี่

โค้ดหลอกของเรามีดังนี้;


การดำเนินงานเข้าคิว

Push every input element to the Input Stack

ปฏิบัติการ Dequeue

If ( Output Stack is Empty)
    pop every element in the Input Stack
    and push them to the Output Stack until Input Stack is Empty

pop from Output Stack

ลองจัดคิวจำนวนเต็ม{1, 2, 3}ตามลำดับ จำนวนเต็มจะถูกส่งไปยังInput Stack ( Stack # 1 ) ซึ่งอยู่ทางซ้าย

ป้อนคำอธิบายรูปภาพที่นี่

ถ้าเช่นนั้นจะเกิดอะไรขึ้นถ้าเราทำการ dequeue? เมื่อใดก็ตามที่การดำเนินการ dequeue ถูกดำเนินการคิวจะตรวจสอบว่า Output Stack ว่างเปล่าหรือไม่ (ดูรหัสเทียมด้านบน) หาก Output Stack ว่างเปล่าแล้ว Stack Stack จะถูกแยกออกจากเอาต์พุตเพื่อให้องค์ประกอบ ของ Input Stack จะถูกกลับรายการ ก่อนที่จะส่งคืนค่าสถานะของคิวจะเป็นดังนี้

ป้อนคำอธิบายรูปภาพที่นี่

ตรวจสอบลำดับขององค์ประกอบใน Output Stack (Stack # 2) เห็นได้ชัดว่าเราสามารถป๊อปอัพองค์ประกอบจาก Output Stack เพื่อให้ผลลัพธ์จะเหมือนกับว่าเรา dequeued จากคิว ดังนั้นถ้าเราดำเนินการถอนสองครั้งแรกเราจะได้รับ{1, 2}ตามลำดับ จากนั้นองค์ประกอบ 3 จะเป็นองค์ประกอบเดียวของ Output Stack และ Input Stack จะว่างเปล่า หากเราจัดคิวองค์ประกอบ 4 และ 5 สถานะของคิวจะเป็นดังนี้

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้ Output Stack ไม่ว่างเปล่าและถ้าเราทำการ dequeue จะมีเพียง 3 อันที่โผล่ออกมาจาก Output Stack จากนั้นรัฐจะถูกมองว่าเป็นด้านล่าง;

ป้อนคำอธิบายรูปภาพที่นี่

อีกครั้งถ้าเราดำเนินการถอนสองครั้งเพิ่มเติมในการดำเนินการถอนคิวครั้งแรกคิวจะตรวจสอบว่า Output Stack ว่างเปล่าซึ่งเป็นจริง จากนั้นป๊อปอัพอิลิเมนต์ของอินพุตสแต็กและดันไปที่เอ้าท์พุทสแต็คเพราะกองที่ว่างเปล่าจากนั้นสถานะของคิวจะเป็นดังนี้

ป้อนคำอธิบายรูปภาพที่นี่

ง่ายต่อการมองเห็นผลลัพธ์ของการดำเนินการสองคิวจะเป็น {4, 5}

C - การใช้คิวสร้างด้วยสองกอง

นี่คือการดำเนินการใน Java ฉันจะไม่ใช้การใช้งานของกองซ้อนที่มีอยู่แล้วดังนั้นตัวอย่างที่นี่จะสร้างล้อใหม่

C - 1) ชั้น MyStack: การใช้งานสแต็กง่าย

public class MyStack<T> {

    // inner generic Node class
    private class Node<T> {
        T data;
        Node<T> next;

        public Node(T data) {
            this.data = data;
        }
    }

    private Node<T> head;
    private int size;

    public void push(T e) {
        Node<T> newElem = new Node(e);

        if(head == null) {
            head = newElem;
        } else {
            newElem.next = head;
            head = newElem;     // new elem on the top of the stack
        }

        size++;
    }

    public T pop() {
        if(head == null)
            return null;

        T elem = head.data;
        head = head.next;   // top of the stack is head.next

        size--;

        return elem;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public void printStack() {
        System.out.print("Stack: ");

        if(size == 0)
            System.out.print("Empty !");
        else
            for(Node<T> temp = head; temp != null; temp = temp.next)
                System.out.printf("%s ", temp.data);

        System.out.printf("\n");
    }
}

C - 2) คลาส MyQueue: การนำคิวไปใช้โดยใช้สองกอง

public class MyQueue<T> {

    private MyStack<T> inputStack;      // for enqueue
    private MyStack<T> outputStack;     // for dequeue
    private int size;

    public MyQueue() {
        inputStack = new MyStack<>();
        outputStack = new MyStack<>();
    }

    public void enqueue(T e) {
        inputStack.push(e);
        size++;
    }

    public T dequeue() {
        // fill out all the Input if output stack is empty
        if(outputStack.isEmpty())
            while(!inputStack.isEmpty())
                outputStack.push(inputStack.pop());

        T temp = null;
        if(!outputStack.isEmpty()) {
            temp = outputStack.pop();
            size--;
        }

        return temp;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

}

C - 3) รหัสการสาธิต

public class TestMyQueue {

    public static void main(String[] args) {
        MyQueue<Integer> queue = new MyQueue<>();

        // enqueue integers 1..3
        for(int i = 1; i <= 3; i++)
            queue.enqueue(i);

        // execute 2 dequeue operations 
        for(int i = 0; i < 2; i++)
            System.out.println("Dequeued: " + queue.dequeue());

        // enqueue integers 4..5
        for(int i = 4; i <= 5; i++)
            queue.enqueue(i);

        // dequeue the rest
        while(!queue.isEmpty())
            System.out.println("Dequeued: " + queue.dequeue());
    }

}

C - 4) ตัวอย่างผลลัพธ์

Dequeued: 1
Dequeued: 2
Dequeued: 3
Dequeued: 4
Dequeued: 5

18
ฉันจะ +1 ตลอดทั้งวันถ้าทำได้ ฉันไม่สามารถเข้าใจได้ว่ามันถูกตัดเวลาอย่างคงที่ ภาพประกอบของคุณล้างสิ่งต่างๆโดยเฉพาะอย่างยิ่งส่วนหนึ่งของการปล่อยให้องค์ประกอบที่เหลืออยู่ในสแต็กเอาท์พุทและเติมเฉพาะเมื่อมันหมด
Shane McQuillan

1
สิ่งนี้ช่วยป้องกันข้อผิดพลาดการหมดเวลาที่ฉันได้รับระหว่างการป๊อป ฉันวางองค์ประกอบกลับไปในสแต็กดั้งเดิม แต่ไม่จำเป็นต้องทำเช่นนั้น รุ่งโรจน์!
ปราณี Bankar

2
ความคิดเห็นทั้งหมดควรเป็นแบบอย่างหลังจากความคิดเห็นนี้
lolololol ol

4
ฉันไม่ต้องการทางออกสำหรับเรื่องนี้เพียงแค่เรียกดู ... แต่เมื่อฉันเห็นคำตอบเช่นนี้ฉันก็ตกหลุมรัก .. คำตอบยอดเยี่ยม !!!
ไม่ฝักใฝ่ฝ่ายใด

80

คุณสามารถจำลองคิวโดยใช้เพียงหนึ่งสแต็ก สแต็ก (ชั่วคราว) ที่สองสามารถจำลองได้โดยสแต็คการเรียกของการเรียกซ้ำไปยังวิธีการแทรก

หลักการยังคงเหมือนเดิมเมื่อแทรกองค์ประกอบใหม่ลงในคิว:

  • คุณต้องถ่ายโอนองค์ประกอบจากหนึ่งกองไปยังอีกกองชั่วคราวเพื่อกลับรายการของพวกเขา
  • จากนั้นดันองค์ประกอบใหม่ที่จะแทรกลงบนสแต็กชั่วคราว
  • จากนั้นโอนองค์ประกอบกลับไปที่สแต็คเดิม
  • องค์ประกอบใหม่จะอยู่ที่ด้านล่างของสแต็กและองค์ประกอบที่เก่าแก่ที่สุดอยู่ด้านบน (ก่อนจะถูกตอก)

คลาส Queue ที่ใช้เพียงหนึ่ง Stack จะเป็นดังนี้:

public class SimulatedQueue<E> {
    private java.util.Stack<E> stack = new java.util.Stack<E>();

    public void insert(E elem) {
        if (!stack.empty()) {
            E topElem = stack.pop();
            insert(elem);
            stack.push(topElem);
        }
        else
            stack.push(elem);
    }

    public E remove() {
        return stack.pop();
    }
}

51
อาจเป็นรหัสที่ดูสง่างาม แต่มันไม่มีประสิทธิภาพมาก (แทรก O (n ** 2)) และยังคงมีสองกองหนึ่งในกองและหนึ่งในกองซ้อนโทร @ pythonquick ชี้ให้เห็น สำหรับอัลกอริทึมที่ไม่ใช่แบบเรียกซ้ำคุณสามารถคว้าหนึ่ง "สแต็ก" พิเศษจากสแต็กการโทรเป็นภาษาที่รองรับการเรียกซ้ำ
Antti Huima

1
@ antti.huima และคุณจะอธิบายว่านี่เป็นส่วนเสริมกำลังสองได้อย่างไร! จากสิ่งที่ฉันเข้าใจการแทรกจะเป็นการดำเนินการแบบป็อปและพุชดังนั้นจึงเป็นอัลกอริธึมเชิงเส้น O (n)
LP_

1
@LP_ ใช้เวลากำลังสอง O (n ^ 2) เพื่อแทรกn itemsในคิวโดยใช้โครงสร้างข้อมูลข้างต้น รวมผลในการ(1 + 2 + 4 + 8 + .... + 2(n-1)) ~O(n^2)ฉันหวังว่าคุณจะได้รับจุด
Ankit Kumar

1
@ antti.huima คุณกำลังพูดถึงความซับซ้อนของฟังก์ชั่นแทรก (คุณพูดว่า "O (n 2) insert" - คุณอาจหมายถึง "O (n 2) fill") ตามแบบแผน "การแทรกความซับซ้อน" คือเวลาที่ใช้ในการแทรกครั้งเดียวซึ่งเป็นเส้นตรงในจำนวนองค์ประกอบที่มีอยู่แล้ว ถ้าเราพูดในเวลาที่ต้องการใส่nรายการเราจะพูดว่า hashtable มีการแทรกแบบเส้นตรง ซึ่งไม่ใช่กรณี
LP_

2
คุณใช้กองซ้อนเป็นกอง ซึ่งหมายความว่าหากมีรายการจำนวนมากอยู่ในสแต็กคุณสามารถท้ายด้วยสแต็คโอเวอร์โฟลว์ - มันเกือบจะเหมือนโซลูชันที่ออกแบบมาสำหรับไซต์นี้!
UKMonkey

11

ความซับซ้อนของเวลาจะยิ่งแย่ลง การใช้คิวที่ดีทำทุกอย่างในเวลาคงที่

แก้ไข

ไม่แน่ใจว่าทำไมคำตอบของฉันถูกลงที่นี่ หากเราโปรแกรมเราใส่ใจกับความซับซ้อนของเวลาและการใช้สแต็คมาตรฐานสองแบบเพื่อสร้างคิวนั้นไม่มีประสิทธิภาพ มันเป็นจุดที่ถูกต้องและเกี่ยวข้องมาก ถ้ามีคนอื่นรู้สึกว่าต้องลงคะแนนมากกว่านี้ฉันก็อยากจะรู้ว่าทำไม

รายละเอียดเพิ่มเติมเล็กน้อย : ทำไมการใช้สองสแต็คนั้นแย่กว่าคิว: ถ้าคุณใช้สองกองและมีคนโทร dequeue ในขณะที่กล่องขาออกว่างคุณต้องใช้เวลาเชิงเส้นเพื่อไปที่ด้านล่างของกล่องจดหมาย (ดังที่คุณเห็น ในรหัสของเดฟ)

คุณสามารถใช้คิวเป็นรายการที่เชื่อมโยงโดยลำพัง (แต่ละองค์ประกอบชี้ไปที่องค์ประกอบที่แทรกถัดไป) ทำให้ตัวชี้พิเศษไปยังองค์ประกอบแทรกล่าสุดสำหรับการผลักดัน (หรือทำให้มันเป็นรายการวงจร) การใช้คิวและ dequeue ในโครงสร้างข้อมูลนี้ทำได้ง่ายมากในเวลาคงที่ นั่นคือเวลาคงที่ที่เลวร้ายที่สุดไม่ใช่ค่าตัดจำหน่าย และเนื่องจากความคิดเห็นที่ดูเหมือนจะขอคำชี้แจงนี้เวลาคงที่ที่เลวร้ายที่สุดกรณีดีกว่าเวลาคงที่ตัดจำหน่ายอย่างเคร่งครัด


ไม่ใช่ในกรณีทั่วไป คำตอบของไบรอันอธิบายคิวซึ่งจะมี enqueue คงตัดจำหน่ายและการดำเนินงาน dequeue
Daniel Spiewak

นั่นเป็นเรื่องจริง คุณมีความซับซ้อนของตัวพิมพ์เล็กและใหญ่โดยเฉลี่ยในเวลาเดียวกัน แต่ค่าเริ่มต้นมักจะเป็นกรณีที่เลวร้ายที่สุดต่อการดำเนินการและนี่คือ O (n) โดยที่ n คือขนาดปัจจุบันของโครงสร้าง
ไทเลอร์

1
กรณีที่เลวร้ายที่สุดยังสามารถตัดจำหน่าย ตัวอย่างเช่นอาร์เรย์แบบไดนามิกที่ไม่แน่นอน (เวกเตอร์) มักจะถูกพิจารณาว่ามีเวลาแทรกคงที่แม้ว่าจะต้องใช้การดำเนินการปรับขนาดและคัดลอกราคาแพงทุก ๆ ครั้ง
Daniel Spiewak

1
"กรณีที่แย่ที่สุด" และ "ค่าตัดจำหน่าย" เป็นความซับซ้อนของเวลาสองประเภท ไม่เหมาะสมที่จะบอกว่า "กรณีที่เลวร้ายที่สุดสามารถตัดจำหน่ายได้" - หากคุณสามารถทำให้กรณีที่เลวร้ายที่สุด = ตัดจำหน่ายแล้วนี่จะเป็นการปรับปรุงที่สำคัญ คุณจะพูดถึงกรณีที่เลวร้ายที่สุดโดยไม่มีค่าเฉลี่ย
Tyler

ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงโดย O (1) กรณีที่เลวร้ายที่สุดคือ "ดีกว่าอย่างเคร่งครัด" มากกว่าชุดค่าเฉลี่ย O (1) กรณีและ O (n) กรณีที่เลวร้ายที่สุด ปัจจัยการปรับสเกลคงที่สำคัญ โครงสร้างข้อมูลซึ่งหากมี N รายการอาจจำเป็นต้องบรรจุใหม่หลังจากการดำเนินการ N ครั้งในเวลา N microseconds และใช้เวลาหนึ่ง microsecond ต่อการดำเนินการหนึ่งครั้งอาจมีประโยชน์มากกว่าหนึ่งมิลลิวินาทีสำหรับแต่ละการดำเนินการแม้ หากขนาดข้อมูลจะขยายไปยังรายการนับล้าน (หมายความว่าการดำเนินการบางอย่างจะใช้เวลาหลายวินาที)
supercat

8

ให้คิวที่จะนำมาใช้เป็น q และกองที่ใช้ในการดำเนินการ q เป็น stack1 และ stack2

q สามารถดำเนินการได้สองวิธี:

วิธีที่ 1 (โดยทำให้การดำเนินการ enQueue มีราคาแพง)

วิธีการนี้ทำให้แน่ใจได้ว่าองค์ประกอบที่เพิ่งป้อนเข้ามาจะอยู่ที่ด้านบนสุดของสแต็ก 1 เสมอดังนั้นการดำเนินการ deQueue จะปรากฏขึ้นจากสแต็ก 1 ในการวางองค์ประกอบที่ด้านบนของ stack1 จะใช้ stack2

enQueue(q, x)
1) While stack1 is not empty, push everything from stack1 to stack2.
2) Push x to stack1 (assuming size of stacks is unlimited).
3) Push everything back to stack1.
deQueue(q)
1) If stack1 is empty then error
2) Pop an item from stack1 and return it.

วิธีที่ 2 (โดยทำให้การดำเนินการ deQueue แพง)

ในวิธีนี้ในการดำเนินการคิวองค์ประกอบใหม่จะถูกป้อนที่ด้านบนของสแต็ค 1 ในการดำเนินการยกเลิกคิวหาก stack2 ว่างเปล่าจากนั้นองค์ประกอบทั้งหมดจะถูกย้ายไปที่ stack2 และในที่สุดก็กลับมาด้านบนของ stack2

enQueue(q,  x)
 1) Push x to stack1 (assuming size of stacks is unlimited).

deQueue(q)
 1) If both stacks are empty then error.
 2) If stack2 is empty
   While stack1 is not empty, push everything from stack1 to stack2.
 3) Pop the element from stack2 and return it.

วิธีที่ 2 ดีกว่าวิธีที่ 1 แน่นอนวิธีที่ 1 ย้ายองค์ประกอบทั้งหมดสองครั้งในการดำเนินการ enQueue ในขณะที่วิธีที่ 2 (ในการดำเนินการ deQueue) จะย้ายองค์ประกอบหนึ่งครั้งและย้ายองค์ประกอบเฉพาะเมื่อ stack2 ว่างเปล่า


ไม่มีวิธีแก้ไขปัญหาที่ฉันเข้าใจยกเว้นวิธีการของคุณ 2 ฉันชอบวิธีที่คุณอธิบายด้วยวิธีการจัดคิวและการทำคิวด้วยขั้นตอน
theGreenCabbage


3

ทางออกใน c #

public class Queue<T> where T : class
{
    private Stack<T> input = new Stack<T>();
    private Stack<T> output = new Stack<T>();
    public void Enqueue(T t)
    {
        input.Push(t);
    }

    public T Dequeue()
    {
        if (output.Count == 0)
        {
            while (input.Count != 0)
            {
                output.Push(input.Pop());
            }
        }

        return output.Pop();
    }
}

2

สองกองในคิวจะถูกกำหนดเป็นstack1และstack2

Enqueue: องค์ประกอบที่มีค่าจะถูกส่งไปยังstack1 เสมอ

Dequeue: ด้านบนของstack2สามารถถูกเปิดออกเนื่องจากมันเป็นองค์ประกอบแรกที่ใส่เข้าไปในคิวเมื่อstack2ไม่ว่างเปล่า เมื่อstack2ว่างเปล่าเราป๊อปอัพองค์ประกอบทั้งหมดจากstack1และกดลงในstack2หนึ่งต่อหนึ่ง อิลิเมนต์แรกในคิวถูกส่งไปที่ด้านล่างของสแต็ก 1 มันสามารถโผล่ออกมาได้โดยตรงหลังจากที่กดและกดการดำเนินการเพราะมันอยู่ด้านบนของสแต็ค 2

ต่อไปนี้เป็นรหัสตัวอย่าง C ++ เดียวกัน:

template <typename T> class CQueue
{
public:
    CQueue(void);
    ~CQueue(void);

    void appendTail(const T& node); 
    T deleteHead();                 

private:
    stack<T> stack1;
    stack<T> stack2;
};

template<typename T> void CQueue<T>::appendTail(const T& element) {
    stack1.push(element);
} 

template<typename T> T CQueue<T>::deleteHead() {
    if(stack2.size()<= 0) {
        while(stack1.size()>0) {
            T& data = stack1.top();
            stack1.pop();
            stack2.push(data);
        }
    }


    if(stack2.size() == 0)
        throw new exception("queue is empty");


    T head = stack2.top();
    stack2.pop();


    return head;
}

การแก้ปัญหานี้จะถูกยืมมาจากบล็อกของฉัน การวิเคราะห์อย่างละเอียดยิ่งขึ้นด้วยการจำลองการทำงานทีละขั้นตอนมีอยู่ในหน้าเว็บบล็อกของฉัน


2

คุณจะต้องโผล่ทุกอย่างออกจากสแต็กแรกเพื่อให้ได้องค์ประกอบด้านล่าง จากนั้นนำทั้งหมดกลับสู่สแต็กที่สองสำหรับการดำเนินการ "dequeue" ทุกครั้ง


3
ใช่คุณถูก. ฉันสงสัยว่าคุณได้รับการโหวตมากมายได้อย่างไร ฉันตอบคำตอบของคุณแล้ว
Binita Bharati

มันน่าขนลุกที่เห็นว่านี่เป็นคำตอบสุดท้ายของเขาและมันก็เป็นสิบปีแล้ว
Shanu Gupta

2

สำหรับนักพัฒนา c # ที่นี่เป็นโปรแกรมที่สมบูรณ์:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QueueImplimentationUsingStack
{
    class Program
    {
        public class Stack<T>
        {
            public int size;
            public Node<T> head;
            public void Push(T data)
            {
                Node<T> node = new Node<T>();
                node.data = data;
                if (head == null)
                    head = node;
                else
                {
                    node.link = head;
                    head = node;
                }
                size++;
                Display();
            }
            public Node<T> Pop()
            {
                if (head == null)
                    return null;
                else
                {
                    Node<T> temp = head;
                    //temp.link = null;
                    head = head.link;
                    size--;
                    Display();
                    return temp;
                }
            }
            public void Display()
            {
                if (size == 0)
                    Console.WriteLine("Empty");
                else
                {
                    Console.Clear();
                    Node<T> temp = head;
                    while (temp!= null)
                    {
                        Console.WriteLine(temp.data);
                        temp = temp.link;
                    }
                }
            }
        }

        public class Queue<T>
        {
            public int size;
            public Stack<T> inbox;
            public Stack<T> outbox;
            public Queue()
            {
                inbox = new Stack<T>();
                outbox = new Stack<T>();
            }
            public void EnQueue(T data)
            {
                inbox.Push(data);
                size++;
            }
            public Node<T> DeQueue()
            {
                if (outbox.size == 0)
                {
                    while (inbox.size != 0)
                    {
                        outbox.Push(inbox.Pop().data);
                    }
                }
                Node<T> temp = new Node<T>();
                if (outbox.size != 0)
                {
                    temp = outbox.Pop();
                    size--;
                }
                return temp;
            }

        }
        public class Node<T>
        {
            public T data;
            public Node<T> link;
        }

        static void Main(string[] args)
        {
            Queue<int> q = new Queue<int>();
            for (int i = 1; i <= 3; i++)
                q.EnQueue(i);
           // q.Display();
            for (int i = 1; i < 3; i++)
                q.DeQueue();
            //q.Display();
            Console.ReadKey();
        }
    }
}

2

ใช้การดำเนินการของคิวต่อไปนี้โดยใช้สแต็ก

push (x) - ผลักองค์ประกอบ x ไปด้านหลังของคิว

pop () - ลบองค์ประกอบออกจากด้านหน้าของคิว

peek () - รับองค์ประกอบด้านหน้า

empty () - ส่งคืนว่าคิวว่างเปล่าหรือไม่

ป้อนคำอธิบายรูปภาพที่นี่

class MyQueue {

  Stack<Integer> input;
  Stack<Integer> output;

  /** Initialize your data structure here. */
  public MyQueue() {
    input = new Stack<Integer>();
    output = new Stack<Integer>();
  }

  /** Push element x to the back of queue. */
  public void push(int x) {
    input.push(x);
  }

  /** Removes the element from in front of queue and returns that element. */
  public int pop() {
    peek();
    return output.pop();
  }

  /** Get the front element. */
  public int peek() {
    if(output.isEmpty()) {
        while(!input.isEmpty()) {
            output.push(input.pop());
        }
    }
    return output.peek();
  }

  /** Returns whether the queue is empty. */
  public boolean empty() {
    return input.isEmpty() && output.isEmpty();
  }
}

1
// Two stacks s1 Original and s2 as Temp one
    private Stack<Integer> s1 = new Stack<Integer>();
    private Stack<Integer> s2 = new Stack<Integer>();

    /*
     * Here we insert the data into the stack and if data all ready exist on
     * stack than we copy the entire stack s1 to s2 recursively and push the new
     * element data onto s1 and than again recursively call the s2 to pop on s1.
     * 
     * Note here we can use either way ie We can keep pushing on s1 and than
     * while popping we can remove the first element from s2 by copying
     * recursively the data and removing the first index element.
     */
    public void insert( int data )
    {
        if( s1.size() == 0 )
        {
            s1.push( data );
        }
        else
        {
            while( !s1.isEmpty() )
            {
                s2.push( s1.pop() );
            }
            s1.push( data );
            while( !s2.isEmpty() )
            {
                s1.push( s2.pop() );
            }
        }
    }

    public void remove()
    {
        if( s1.isEmpty() )
        {
            System.out.println( "Empty" );
        }
        else
        {
            s1.pop();

        }
    }

1

การใช้งานคิวโดยใช้สองกองใน Swift:

struct Stack<Element> {
    var items = [Element]()

    var count : Int {
        return items.count
    }

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.removeLast()
    }

    func peek() -> Element? {
        return items.last
    }
}

struct Queue<Element> {
    var inStack = Stack<Element>()
    var outStack = Stack<Element>()

    mutating func enqueue(_ item: Element) {
        inStack.push(item)
    }

    mutating func dequeue() -> Element? {
        fillOutStack() 
        return outStack.pop()
    }

    mutating func peek() -> Element? {
        fillOutStack()
        return outStack.peek()
    }

    private mutating func fillOutStack() {
        if outStack.count == 0 {
            while inStack.count != 0 {
                outStack.push(inStack.pop()!)
            }
        }
    }
}

1

ในขณะที่คุณจะได้รับการโพสต์จำนวนมากที่เกี่ยวข้องกับการใช้คิวที่มีสองกอง: 1. โดยการทำให้กระบวนการ enQueue มีค่าใช้จ่ายมากขึ้น 2. หรือโดยการทำให้กระบวนการ deQueue มีราคาแพงมากขึ้น

https://www.geeksforgeeks.org/queue-using-stacks/

วิธีหนึ่งที่สำคัญที่ฉันค้นพบจากโพสต์ด้านบนคือการสร้างคิวด้วยโครงสร้างข้อมูลสแต็กเท่านั้นและสแต็กการเรียกซ้ำ

ในขณะที่หนึ่งสามารถยืนยันว่าแท้จริงนี้ยังคงใช้สองสแต็ก แต่แล้วความนึกคิดนี้ใช้เพียงหนึ่งโครงสร้างข้อมูลสแต็ค

ด้านล่างนี้เป็นคำอธิบายของปัญหา:

  1. ประกาศสแต็กเดี่ยวสำหรับ enQueuing และ deQueing ข้อมูลแล้วพุชข้อมูลลงในสแต็ก

  2. ในขณะที่ deQueueing มีสภาพพื้นฐานที่องค์ประกอบของสแต็คจะปรากฏขึ้นเมื่อขนาดของสแต็คเป็น 1 เพื่อให้แน่ใจว่าไม่มีการล้นสแต็คในระหว่างการเรียกซ้ำ deQueue

  3. ขณะที่ deQueueing ปรากฏข้อมูลจากด้านบนสุดของสแต็ก โดยหลักการแล้วองค์ประกอบนี้จะเป็นองค์ประกอบที่มีอยู่ที่ด้านบนสุดของสแต็ก ทีนี้เมื่อทำเสร็จแล้วให้เรียกใช้ฟังก์ชัน deQueue ซ้ำแล้วดันองค์ประกอบที่โผล่ขึ้นมากลับเข้าไปในกองซ้อน

รหัสจะมีลักษณะดังนี้:

if (s1.isEmpty())
System.out.println("The Queue is empty");
        else if (s1.size() == 1)
            return s1.pop();
        else {
            int x = s1.pop();
            int result = deQueue();
            s1.push(x);
            return result;

วิธีนี้คุณสามารถสร้างคิวโดยใช้โครงสร้างข้อมูลสแต็กเดียวและกองการเรียกซ้ำ


1

ด้านล่างเป็นวิธีแก้ปัญหาในภาษาจาวาสคริปต์โดยใช้ไวยากรณ์ ES6

Stack.js

//stack using array
class Stack {
  constructor() {
    this.data = [];
  }

  push(data) {
    this.data.push(data);
  }

  pop() {
    return this.data.pop();
  }

  peek() {
    return this.data[this.data.length - 1];
  }

  size(){
    return this.data.length;
  }
}

export { Stack };

QueueUsingTwoStacks.js

import { Stack } from "./Stack";

class QueueUsingTwoStacks {
  constructor() {
    this.stack1 = new Stack();
    this.stack2 = new Stack();
  }

  enqueue(data) {
    this.stack1.push(data);
  }

  dequeue() {
    //if both stacks are empty, return undefined
    if (this.stack1.size() === 0 && this.stack2.size() === 0)
      return undefined;

    //if stack2 is empty, pop all elements from stack1 to stack2 till stack1 is empty
    if (this.stack2.size() === 0) {
      while (this.stack1.size() !== 0) {
        this.stack2.push(this.stack1.pop());
      }
    }

    //pop and return the element from stack 2
    return this.stack2.pop();
  }
}

export { QueueUsingTwoStacks };

ด้านล่างคือการใช้งาน:

index.js

import { StackUsingTwoQueues } from './StackUsingTwoQueues';

let que = new QueueUsingTwoStacks();
que.enqueue("A");
que.enqueue("B");
que.enqueue("C");

console.log(que.dequeue());  //output: "A"

นี่มันบั๊กแล้ว หากคุณจัดคิวองค์ประกอบเพิ่มเติมหลังจาก dequeueing คุณจะใส่องค์ประกอบเหล่าstack1นั้น เมื่อคุณไปที่dequeueอีกครั้งคุณจะย้ายรายการstack2เหล่านั้นไปไว้ข้างหน้าโดยวางสิ่งที่มีอยู่แล้ว
Alexander - Reinstate Monica

0

ฉันจะตอบคำถามนี้ใน Go เพราะ Go ไม่มีคอลเลกชันมากมายในไลบรารีมาตรฐาน

เนื่องจากสแต็กนั้นใช้งานได้ง่ายมากฉันคิดว่าฉันลองและใช้สแต็คสองตัวเพื่อให้ได้คิวคู่ที่สิ้นสุด เพื่อให้เข้าใจได้ดียิ่งขึ้นว่าฉันมาถึงคำตอบได้อย่างไรฉันได้แบ่งการใช้งานเป็นสองส่วนส่วนแรกคือหวังว่าจะเข้าใจได้ง่ายขึ้น แต่ก็ไม่สมบูรณ์

type IntQueue struct {
    front       []int
    back        []int
}

func (q *IntQueue) PushFront(v int) {
    q.front = append(q.front, v)
}

func (q *IntQueue) Front() int {
    if len(q.front) > 0 {
        return q.front[len(q.front)-1]
    } else {
        return q.back[0]
    }
}

func (q *IntQueue) PopFront() {
    if len(q.front) > 0 {
        q.front = q.front[:len(q.front)-1]
    } else {
        q.back = q.back[1:]
    }
}

func (q *IntQueue) PushBack(v int) {
    q.back = append(q.back, v)
}

func (q *IntQueue) Back() int {
    if len(q.back) > 0 {
        return q.back[len(q.back)-1]
    } else {
        return q.front[0]
    }
}

func (q *IntQueue) PopBack() {
    if len(q.back) > 0 {
        q.back = q.back[:len(q.back)-1]
    } else {
        q.front = q.front[1:]
    }
}

เป็นพื้นสองกองที่เราอนุญาตให้ด้านล่างของสแต็คได้รับการจัดการซึ่งกันและกัน ฉันยังใช้การตั้งชื่อแบบแผนการประชุมที่การดำเนินการแบบพุชแบบป๊อปและแบบแอบมองของกองซ้อนมีคำนำหน้า / หลังไม่ว่าพวกเขาจะอ้างถึงด้านหน้าหรือด้านหลังของคิว

ปัญหาของโค้ดข้างต้นคือมันไม่ได้ใช้หน่วยความจำอย่างมีประสิทธิภาพ ที่จริงแล้วมันจะเติบโตอย่างไม่มีที่สิ้นสุดจนกว่าคุณจะหมดพื้นที่ มันแย่มากจริงๆ การแก้ไขสำหรับสิ่งนี้คือการใช้ซ้ำด้านล่างของพื้นที่สแต็คเมื่อทำได้ เราต้องแนะนำออฟเซ็ตเพื่อติดตามสิ่งนี้เนื่องจากชิ้นส่วนในโกไม่สามารถเติบโตได้ด้านหน้าเมื่อหดตัวลง

type IntQueue struct {
    front       []int
    frontOffset int
    back        []int
    backOffset  int
}

func (q *IntQueue) PushFront(v int) {
    if q.backOffset > 0 {
        i := q.backOffset - 1
        q.back[i] = v
        q.backOffset = i
    } else {
        q.front = append(q.front, v)
    }
}

func (q *IntQueue) Front() int {
    if len(q.front) > 0 {
        return q.front[len(q.front)-1]
    } else {
        return q.back[q.backOffset]
    }
}

func (q *IntQueue) PopFront() {
    if len(q.front) > 0 {
        q.front = q.front[:len(q.front)-1]
    } else {
        if len(q.back) > 0 {
            q.backOffset++
        } else {
            panic("Cannot pop front of empty queue.")
        }
    }
}

func (q *IntQueue) PushBack(v int) {
    if q.frontOffset > 0 {
        i := q.frontOffset - 1
        q.front[i] = v
        q.frontOffset = i
    } else {
        q.back = append(q.back, v)
    }
}

func (q *IntQueue) Back() int {
    if len(q.back) > 0 {
        return q.back[len(q.back)-1]
    } else {
        return q.front[q.frontOffset]
    }
}

func (q *IntQueue) PopBack() {
    if len(q.back) > 0 {
        q.back = q.back[:len(q.back)-1]
    } else {
        if len(q.front) > 0 {
            q.frontOffset++
        } else {
            panic("Cannot pop back of empty queue.")
        }
    }
}

มันมีฟังก์ชั่นเล็ก ๆ มากมาย แต่ฟังก์ชั่นทั้ง 6 ฟังก์ชั่น 3 ตัวนั้นเป็นเพียงแค่ฟังก์ชั่นอื่น ๆ


คุณกำลังใช้อาร์เรย์ที่นี่ ฉันไม่เห็นว่ากองของคุณอยู่ที่ไหน
melpomene

@melpomene ตกลงถ้าคุณมองใกล้ ๆ คุณจะสังเกตเห็นว่าการดำเนินการเดียวที่ฉันกำลังแสดงคือการเพิ่ม / ลบองค์ประกอบสุดท้ายในอาร์เรย์ กล่าวอีกนัยหนึ่งคือผลักและ popping สำหรับความตั้งใจและวัตถุประสงค์ทั้งหมดสิ่งเหล่านี้คือกอง แต่ถูกใช้งานโดยใช้อาร์เรย์
John Leidegren

@melpomene จริงๆแล้วมันแค่ครึ่งเดียวเท่านั้น ฉันอนุญาตให้แก้ไขสแต็กในแบบที่ไม่ได้มาตรฐานจากล่างขึ้นบนภายใต้เงื่อนไขบางประการ
John Leidegren

0

นี่คือทางออกของฉันใน java โดยใช้ linkedlist

class queue<T>{
static class Node<T>{
    private T data;
    private Node<T> next;
    Node(T data){
        this.data = data;
        next = null;
    }
}
Node firstTop;
Node secondTop;

void push(T data){
    Node temp = new Node(data);
    temp.next = firstTop;
    firstTop = temp;
}

void pop(){
    if(firstTop == null){
        return;
    }
    Node temp = firstTop;
    while(temp != null){
        Node temp1 = new Node(temp.data);
        temp1.next = secondTop;
        secondTop = temp1;
        temp = temp.next;
    }
    secondTop = secondTop.next;
    firstTop = null;
    while(secondTop != null){
        Node temp3 = new Node(secondTop.data);
        temp3.next = firstTop;
        firstTop = temp3;
        secondTop = secondTop.next;
    }
}

}

หมายเหตุ:ในกรณีนี้การดำเนินการแบบ pop ใช้เวลานานมาก ดังนั้นฉันจะไม่แนะนำให้สร้างคิวโดยใช้สองกอง


0

ด้วยO(1) dequeue()ซึ่งเหมือนกับคำตอบของ pythonquick :

// time: O(n), space: O(n)
enqueue(x):
    if stack.isEmpty():
        stack.push(x)
        return
    temp = stack.pop()
    enqueue(x)
    stack.push(temp)

// time: O(1)
x dequeue():
    return stack.pop()

ด้วยO(1) enqueue()(ไม่ได้กล่าวถึงในโพสต์นี้ดังนั้นคำตอบนี้) ซึ่งใช้การย้อนรอยเพื่อทำให้ฟองสบู่ขึ้นและส่งคืนรายการที่ต่ำที่สุด

// O(1)
enqueue(x):
    stack.push(x)

// time: O(n), space: O(n)
x dequeue():
    temp = stack.pop()
    if stack.isEmpty():
        x = temp
    else:
        x = dequeue()
        stack.push(temp)
    return x

เห็นได้ชัดว่ามันเป็นแบบฝึกหัดที่ดีเนื่องจากไม่มีประสิทธิภาพ แต่ก็ยังสวยงาม


0

** โซลูชัน JS ง่าย ๆ **

  • หมายเหตุ: ฉันเอาความคิดจากคนอื่น ๆ แสดงความคิดเห็น

/*

enQueue(q,  x)
 1) Push x to stack1 (assuming size of stacks is unlimited).

deQueue(q)
 1) If both stacks are empty then error.
 2) If stack2 is empty
   While stack1 is not empty, push everything from stack1 to stack2.
 3) Pop the element from stack2 and return it.

*/
class myQueue {
    constructor() {
        this.stack1 = [];
        this.stack2 = [];
    }

    push(item) {
        this.stack1.push(item)
    }

    remove() {
        if (this.stack1.length == 0 && this.stack2.length == 0) {
            return "Stack are empty"
        }

        if (this.stack2.length == 0) {

            while (this.stack1.length != 0) {
                this.stack2.push(this.stack1.pop())
            }
        }
        return this.stack2.pop()
    }


    peek() {
        if (this.stack2.length == 0 && this.stack1.length == 0) {
            return 'Empty list'
        }

        if (this.stack2.length == 0) {
            while (this.stack1.length != 0) {
                this.stack2.push(this.stack1.pop())
            }
        }

        return this.stack2[0]
    }

    isEmpty() {
        return this.stack2.length === 0 && this.stack1.length === 0;
    }

}

const q = new myQueue();
q.push(1);
q.push(2);
q.push(3);
q.remove()

console.log(q)


-1
public class QueueUsingStacks<T>
{
    private LinkedListStack<T> stack1;
    private LinkedListStack<T> stack2;

    public QueueUsingStacks()
    {
        stack1=new LinkedListStack<T>();
        stack2 = new LinkedListStack<T>();

    }
    public void Copy(LinkedListStack<T> source,LinkedListStack<T> dest )
    {
        while(source.Head!=null)
        {
            dest.Push(source.Head.Data);
            source.Head = source.Head.Next;
        }
    }
    public void Enqueue(T entry)
    {

       stack1.Push(entry);
    }
    public T Dequeue()
    {
        T obj;
        if (stack2 != null)
        {
            Copy(stack1, stack2);
             obj = stack2.Pop();
            Copy(stack2, stack1);
        }
        else
        {
            throw new Exception("Stack is empty");
        }
        return obj;
    }

    public void Display()
    {
        stack1.Display();
    }


}

สำหรับการดำเนินงานคิวงานทุกครั้งเราเพิ่มไปที่ด้านบนสุดของสแต็ก 1 สำหรับ dequeue ทุกครั้งเราจะลบเนื้อหาของ stack1 ลงใน stack2 และลบองค์ประกอบที่อยู่ด้านบนของ stack ความซับซ้อนของเวลาคือ O (n) สำหรับ dequeue เนื่องจากเราต้องคัดลอก stack1 ไปยัง stack2 ความซับซ้อนของเวลาของการเข้าคิวเป็นเหมือนสแต็กปกติ


รหัสนี้ไม่มีประสิทธิภาพ (การคัดลอกที่ไม่จำเป็น) และใช้งานไม่ได้: if (stack2 != null)เป็นจริงเสมอเนื่องจากstack2มีการสร้างอินสแตนซ์ในตัวสร้าง
melpomene

-2

การใช้คิวในการใช้วัตถุ java.util.Stack สองอัน:

public final class QueueUsingStacks<E> {

        private final Stack<E> iStack = new Stack<>();
        private final Stack<E> oStack = new Stack<>();

        public void enqueue(E e) {
            iStack.push(e);
        }

        public E dequeue() {
            if (oStack.isEmpty()) {
                if (iStack.isEmpty()) {
                    throw new NoSuchElementException("No elements present in Queue");
                }
                while (!iStack.isEmpty()) {
                    oStack.push(iStack.pop());
                }
            }
            return oStack.pop();
        }

        public boolean isEmpty() {
            if (oStack.isEmpty() && iStack.isEmpty()) {
                return true;
            }
            return false;
        }

        public int size() {
            return iStack.size() + oStack.size();
        }

}

3
รหัสนี้มีฟังก์ชั่นเหมือนกับคำตอบของ Dave L. มันไม่ได้เพิ่มอะไรใหม่เลยแม้แต่คำอธิบาย
melpomene

เพิ่มเมธอด isEmpty () และ size () พร้อมกับการจัดการข้อยกเว้นพื้นฐาน ฉันจะแก้ไขเพื่อเพิ่มคำอธิบาย
realPK

1
ไม่มีใครขอวิธีพิเศษเหล่านั้นและพวกเขาก็เล็กน้อย (แต่ละบรรทัดหนึ่ง): return inbox.isEmpty() && outbox.isEmpty()และreturn inbox.size() + outbox.size()ตามลำดับ รหัสของ Dave L. มีข้อผิดพลาดอยู่แล้วเมื่อคุณ dequeue จากคิวที่ว่างเปล่า คำถามเดิมไม่ได้เกี่ยวกับ Java มันเป็นเรื่องของโครงสร้างข้อมูล / อัลกอริทึมโดยทั่วไป การนำ Java ไปใช้นั้นเป็นเพียงภาพประกอบเพิ่มเติม
melpomene

1
นี่เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับผู้ที่ต้องการทำความเข้าใจวิธีสร้างคิวจากสแต็คสองไดอะแกรมส่วนใหญ่ช่วยฉันได้มากกว่าอ่านคำตอบของเดฟ
Kemal Tezer Dilsiz

@melpomene: มันไม่เกี่ยวกับวิธีการเล็กน้อย แต่ต้องการ ส่วนต่อประสานคิวใน Java ขยายวิธีการเหล่านั้นออกจากส่วนต่อประสานการรวบรวมเนื่องจากจำเป็น
realPK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.