5 분 소요



큐 - Queues

큐는 엔트리가 한쪽 끝(뒤쪽)에 insert되고 다른쪽 끝(앞쪽)에서 제거될 수 있는 순서가 지정된 엔트리의 데이터구조다.

  • 특징으로는 선입선출(First-in First-Out)이 있다.



STL Queue Class Template

Queue Class Template는 다음과 같다.


  • pop() (dequeue)
  • push(const Item& entry) (enqueue)
  • empty()
  • size()
  • front()
  • etc.

Queue Errors

Queue overflow

  • 꽉찬 천체 대기열에 아이템을 푸시하려고 시도했을때 결과는 큐 오버플로우 에러


Queue underflow

  • 빈 대기열에서 아이템을 pop하려고 시도한 결과는 큐 언더플로우 에러



Queue Applications

Recognizing Palindromes(회문 인식하기)

Palindromes(회문) : 앞두로 같은 문자열을 읽는다.

Ex : radar, Able was I ere I saw Elba


스택과 큐를 사용해 문자열이 회문인지 여부를 확인할 수 있다.

// FILE: pal.cpp
// Program to test whether an input line is a palindrome. Spaces,
// punctuation, and the difference between upper- and lowercase are ignored.

#include <cassert>    // Provides assert
#include <cctype>     // Provides isalpha, toupper
#include <cstdlib>    // Provides EXIT_SUCCESS
#include <iostream>   // Provides cout, cin, peek
#include <queue>      // Provides the queue template class
#include <stack>      // Provides the stack template class
using namespace std;

int main( )
{
    queue<char> q;
    stack<char> s;
    char letter;            
    queue<char>::size_type mismatches = 0;  // Mismatches between queue and stack
    cout << "Enter a line and I will see if it's a palindrome:" << endl;

    while (cin.peek( ) != '\n')
    {
        cin >> letter;
        if (isalpha(letter))
        {
            q.push(toupper(letter)); //대소문자 무시
            s.push(toupper(letter)); //대소문자 무시
        }
    }

    while ((!q.empty( )) && (!s.empty( )))
    {
        if (q.front( ) != s.top( ))
            ++mismatches;
        q.pop( );
        s.pop( );
    }

    if (mismatches == 0)
        cout << "That is a palindrome." << endl;
    else
        cout << "That is not a palindrome." << endl;    
    return EXIT_SUCCESS;    
}



Queue class의 구현



Array(배열) 구현


배열이 얼마나 많이 사용되었는지 추적하려면 두개의 변수(first, last)가 필요하다.


1. 첫번째 심플한 접근방법

  • first - 현재 사용중인 첫 번째 인덱스를 나타낸다.
  • last - 현재 사용중인 마지막 인덱스를 나타낸다.
  • first와 last는 아이템이 추가되거나 제거될 때 항상 증가한다.
  • 문제점 : 배열에 공간이 있어도 마지막 아이템이 끝나면 새 아이템을 추가할 수 없다.


2. 다른 심플한 접근방법

  • 맨 앞의 항목이 배열에서 삭제되면 나머지 아이템을 모두 왼쪽으로 한칸 이동해 first는 항상 0이된다.
  • 문제점 : 매우 비효율적이다.


3. 원형 배열 접근방법

  • 끝부분 인덱스가 배열의 끝에 도달하면 배열의 전면에서 사용가능한 위치를 재사용할 수 있다.
  • 이때 노드를 결정하는 방법은 0~99니까 총 100개 즉 100으로 나눠주고 나머지에 해당한다.
  • next_index = (current_index + 1) % CAPACITY
  • 이 방법은 first, last, count(꽉찼을때)의 변수를 사용한다.
  • 현재 인덱스가 주어진 다음 인덱스를 계산하기 위해 privite 맴버 함수 next_index를 사용한다.
  • 빈 큐의 경우 last는 유효한 인덱스고 first는 항상 next_index(last)와 같다.
  • 추가설명하자면 1개만 있을때 first와 last가 같은큐고 하나를 pop하면 last는 앞으로 가므로 fisrt는 항상 last다음 인덱스에 있다.


이 방법으로 구현한 코드(헤더와 템플릿파일)는 다음과 같다.


queue_array.h

#ifndef MAIN_SAVITCH_QUEUE1_H
#define MAIN_SAVITCH_QUEUE1_H
#include <cstdlib> // Provides size_t

namespace main_savitch_8B
{
    template <class Item>
    class queue
    {
    public:
        // TYPEDEFS and MEMBER CONSTANTS -- See Appendix E if this fails to compile.
        typedef std::size_t size_type;
        typedef Item value_type;
        static const size_type CAPACITY = 30;
        // CONSTRUCTOR
        queue( ); //템플릿 구현
        // MODIFICATION MEMBER FUNCTIONS
        void pop( ); //템플릿 구현
        void push(const Item& entry); //템플릿 구현
        // CONSTANT MEMBER FUNCTIONS
        bool empty( ) const { return (count == 0); } //바로 구현
        Item front( ) const; //템플릿 구현
        size_type size( ) const { return count; } //바로구현
    private:
        Item data[CAPACITY];     // Circular array 초기화
        size_type first;         // Index of item at front of the queue
        size_type last;          // Index of item at rear of the queue
        size_type count;         // Total number of items in the queue
        // HELPER MEMBER FUNCTION
        size_type next_index(size_type i) const { return (i+1) % CAPACITY; }
    };
}

#include "queue_array.template" // Include the implementation.
#endif


queue_array.template

#include <cassert>  // Provides assert

namespace main_savitch_8B
{
    template <class Item>
    const typename queue<Item>::size_type queue<Item>::CAPACITY;
    
    template <class Item>
    queue<Item>::queue( )
    {
        count = 0; //초기상태
        first = 0; //처음부분
        last = CAPACITY - 1; //last는 마지막을 가르킴
    }

    template <class Item>
    Item queue<Item>::front( ) const
    // Library facilities used: cassert
    {
        assert(!empty( )); //언더플로우 확인
		return data[first]; //front는 first에 들어있는 데이터를 리턴
    }

    template <class Item>
    void queue<Item>::pop( )
    // Library facilities used: cassert
    {
        assert(!empty( )); //언더플로우 확인
        first = next_index(first); //선입선출으로 first를 다음노드로 이동
				// 굳이 데이터 자체를 지우지 않고 first를 이동시켜주는 방식이다
        --count; //count 감소
    }
    
    template <class Item>
    void queue<Item>::push(const Item& entry)
    // Library facilities used: cassert
    {
        assert(size( ) < CAPACITY); //오버플로우 확인
        last = next_index(last); //last를 이동시키고
        data[last] = entry; //데이터를 집어 넣음
        ++count; //count 증가
    }
}



linked list 구현

  • 두개의 포인터와 하나의 카운트 변수를 사용한다.
  • front_ptr - 첫 번째 노드를 가르킴
  • rear_ptr - 마지막 노드를 가르킴
  • count - 목록의 아이템 수를 계산함
  • 기존에 만든 링크드리스트 헤더파일(node.h)을 include한다. linked list 설명 포스트


queue_linkedList.h

#ifndef MAIN_SAVITCH_QUEUE2_H     // Prevent duplicate definition
#define MAIN_SAVITCH_QUEUE2_H
#include <cstdlib>   // Provides std::size_t
#include "node.h"   // Node template class

namespace main_savitch_8C
{
    template <class Item>
    class queue
    {
    public:
        // TYPEDEFS 
        typedef std::size_t size_type;
        typedef Item value_type;
        // CONSTRUCTORS and DESTRUCTOR
        queue( );
		queue(const queue<Item>& source);
		~queue( );
        // MODIFICATION MEMBER FUNCTIONS
        void pop( );
        void push(const Item& entry);
		void operator =(const queue<Item>& source);
        // CONSTANT MEMBER FUNCTIONS
        bool empty( ) const { return (count == 0); }
			Item front( ) const;
			size_type size( ) const { return count; }
    private:
        main_savitch_6B::node<Item> *front_ptr;
        main_savitch_6B::node<Item> *rear_ptr; 
        size_type count;       // Total number of items in the queue
    };
}
#include "queue_linkedList.template" // Include the implementation
     
#endif


queue_linkedList.template

#include <cassert>   // Provides assert
#include "node.h"   // Node template class

namespace main_savitch_8C
{
    template <class Item>
    queue<Item>::queue( )
    {
        count = 0;
        front_ptr = NULL;
    }

    template <class Item>
    queue<Item>::queue(const queue<Item>& source)
    // Library facilities used: node.h
    {
		count = source.count;
		list_copy(source.front_ptr, front_ptr, rear_ptr);
    }

    template <class Item>
    queue<Item>::~queue( )
    {
        list_clear(front_ptr);
    }

    template <class Item>
    void queue<Item>::operator =(const queue<Item>& source)
    // Library facilities used: node.h
    {
        if (this == &source) // Handle self-assignment
            return;
        list_clear(front_ptr);
        list_copy(source.front_ptr, front_ptr, rear_ptr);
        count = source.count;
    }

    template <class Item>
    Item queue<Item>::front( ) const
    // Library facilities used: cassert
    {
        assert(!empty( ));    
        return front_ptr->data( );
    }
    
    template <class Item>
    void queue<Item>::pop( )
    // Library facilities used: cassert, node.h
    {
        assert(!empty( ));
		list_head_remove(front_ptr);
		--count;
    }
    
    template <class Item>
    void queue<Item>::push(const Item& entry)
    // Library facilities used: node.h
    {
        if (empty( ))
        {   // Insert first entry.
            list_head_insert(front_ptr, entry);
            rear_ptr = front_ptr;
        }
        else
        {   // Insert an entry that is not the first.
            list_insert(rear_ptr, entry);
            rear_ptr = rear_ptr->link( );
        }
        ++count;
    }

}


Priority Queues

Priority 큐는 지정된 우선 순위 수준에 따라 항목을 검색할 수 있는 컨테이너 클래스다.

-“out” 순서는 “in” 순서와 같지 않을 수 있다.

댓글남기기