Quay lại   Cộng đồng C Việt > LẬP TRÌNH C++ | LẬP TRÌNH C | LẬP TRÌNH C++0X > Thủ thuật, Tutorials CTDL & Giải thuật

Trả lời
 
Các công cụ đề tài Các chế độ hiển thị
  #1  
Cũ 23-11-2007, 03:42 PM
Avatar của iamvtn
iamvtn iamvtn là offline
Free as the wind
 
Ngày gia nhập: 01 2007
Nơi ở: Somewhere I belong
Bài viết: 168
Unhappy

Ngăn xếp và hàng đợi (Stack and Queue) - Nguyên tắc và cài đặt trên C++


Thứ nhất về stack.

Stack là gì: stack là một kiểu dữ liệu trừu tượng, một cấu trúc có nhiều nút giống như List vậy (Danh sách liên kết) nhưng chúng ta chỉ được phép thêm nút mới vào đỉnh stack (tác vụ push) hoặc xóa nut ở đỉnh stack (tác vụ Pop), hay chúng ta còn gọi cơ chế của stack là cơ chế Lifo (vào trước ra sau). Bạn cứ hình dung stack như một cái băng đạn mỗi nút là một viên đạn, viên đạn nào vào trước thì ra sau, viên nào vào sau thì ra trước. OK
Còn stack để làm gì ư. Stack để giải quyết những vấn đề theo cơ chế LIFO như chuyển một biểu thức dạng trung tố về hậu tố.

Sau đây là mô hình cho Stack-ADT
1. Mô tả dữ liệu:
  • Có nhiều nút cùng một kiểu
  • Có đỉnh stack (top)
2. Mô tả các tác vụ trên stack

initialize

Chức năng: Khởi động stack
Dữ liệu nhập: Không
Dữ liệu xuất: stack top về vị trí khởi đầu.

empty:

Chức năng kiểm tra stack có bị rỗng không.
Dữ liệu nhập: Không
Dữ liệu xuất: True or False (True: khi stack rỗng, False: stack không bị rỗng).

pusth
Chức năng: thêm nút mới tại đỉnh stack
Dữ liệu nhập: nút mới.
Dữ liệu xuất: không

pop

Chức năng: xóa nút tại đỉnh stack.
Dữ liệu nhập: Không.
Điều kiện: stack không bị rỗng.
Dữ liệu xuất: nút bị xóa.

Stacktop:

Chức năng: truy xuất nút tại đỉnh stack.
Dữ liệu nhập: Không.
Điều kiện: stack không bị rỗng.
Dữ liệu xuất: nút tại đỉnh stack.

Stacksize

Chức năng: xác định số nút hiện có trong stack.
Dữ liệu: Không.
Dữ liệu xuất: số nút hiện có trong stack.

Clearstack:

Chức năng: xóa tất cả các nút ở trong stack.
Dữ liệu nhập: không.
Dữ liệu xuất:stack top về vị trí khởi đầu.

copystack:

Chức năng: copystack thành stack thành stack mới.
Dữ liệu nhập: stack nguồn.
Dữ liệu xuất: stack đích giống stack nguồn.

Phương pháp cài đặt stack

Có rất nhiều cách cài đặt một stack nhưng đơn giản cũng như để dễ hình dung nhất là cài đặt bằng mảng hay còn gọi là cài đặt theo kiểu kế tiếp. Ngoài ra còn nhiều cách cài đặt khác như cài đặt bằng Danh sách liên kết (DSLK đơn, DSLK vòng, DSLK kép, DSLK vòng+kép mình thấy cài đặt bằng DSLK vòng +kép là hay nhất)

Sau đây mình sẽ giới thiệu cho bạn về cách cài đặt một stack theo kiểu kế tiếp (bằng mảng đó) minh họa bằng ngôn ngữ C++
const int Max = 100;
class stack
{
      private:
       int top;
      int nodes[Max];
   public:
       stack()  // khoi tao stack
      {
           top = -1; // gan top = -1
      }
       bool empty()// Kiem tra xem stack co rong hay khong
      {
           if(top == -1)
             return true;
         else
             return false;
      }
      void push(int data)
      {
         if(top == Max-1)
             cout<<"Stack bi day";  // truong hop stack bi day
         else
               nodes[++top] = data;
      }
      int pop()
      {
           if(empty())  //truong hop stack bi rong
             cout<<"Stack bi rong ";
         else
             return(nodes[top--]);
      }
      int stacktop()
      {
           if(empty())
              cout<<"Stack bi rong ";
             //su ly truong hop stack bi rong
         else
             return(nodes[top]);
      }
};

Không hiểu gì thì cứ post bài ở tại topic này hoặc liên hệ qua nick Yahoo của mình.
Còn Queue (hay còn gọi là hàng đợi) để tối mình viết nốt. Giờ bận xíu
Trả lời cùng với trích dẫn
  #2  
Cũ 23-11-2007, 10:24 PM
Avatar của iamvtn
iamvtn iamvtn là offline
Free as the wind
 
Ngày gia nhập: 01 2007
Nơi ở: Somewhere I belong
Bài viết: 168
Mặc định

Hàng đợi (Queue)


Hàng đợi (Queue)

[/B]Cũng tương tự như stack, Quêu là một cấu trúc có nhiều nút trải dài từ đầu hàng đợi đến cuối hàng đợi - với hàng đợi chúng ta chỉ được phép thêm nút vào cuối hàng đợi và xóa nút ở đầu hàng đợi nghĩa là việc truy xuất các nút trên hàng đợi xảy ra ở cả hai đầu. Vì nút thêm vào trước sẽ được lấy ra trước nên cấu trúc hàng đợi còn được gọi là cấu trúc FIFO (Firt In First Out). Ví dụ như bạn đi mua vé xem phim với người iu chẳng hạn thì người mua xếp hàng trước sẽ được mua vé trước còn người mua xếp hàng sau thì sẽ mua vé sau.

Và hàng đợi để làm gì ???: Hàng đợi để giải quyết những vấn đề có cơ chế FIFO như dịch vụ quản lý kho, dịch vụ ngân hàng ....

Và sau đây là mô hình Queue-ADT

1. Mô tả dữ liệu:
Có nhiều nút cùng kiểu dữ liệu.
Có đầu hàng đợi (front) và cuối hàng đợi (tail)

2. Mô tả các tác vụ trên hàng đợi:

initialize:
Chức năng: Khởi động hàng đợi.
Dữ liệu nhập: không.
Dữ liệu xuất: front và tail được gán giá trị phù hợp.

empty:

Chức năng: Kiểm tra hàng đợi có bị rỗng không.
Dữ liệu nhập: không.
Dữ liệu xuất True or False. (true khi hàng đợi rỗng, false khi hàng đợi không rỗng)
insert:
Chức năng: thêm nút mới vào cuối hàng đợi.
Dữ liệu nhập: nút mới.
Điều kiện: hàng đợi không bị đầy.
Dữ liệu xuất: không.
remove:
Chức năng: xóa nút ở đầu hàng đợi.
Dữ liệu nhập: không.
Điều kiện: hàng đợi không bị rỗng.
Dữ liệu xuất: nút bị xóa.
queuefront:
Chức năng truy xuất nút ở đầu hàng đợi.
Dữ liệu nhập: không.
Điều kiện: hàng đợi không bị rỗng.
Dữ liệu xuất: nút tại đầu hàng đợi.
queuetail:
Chức năng truy xuất nút tại cuối hàng đợi.
Dữ liệu nhập: không.
Điều kiện: hàng đợi không bị rỗng.
Dữ liệu xuất: nút tại cuối hàng đợi.

queue size:
Chức năng: xác định số nút hiện có trong hàng đợi.
Dữ liệu nhập: không.
Dữ liệu xuất:số nút có trong hàng đợi.

clearqueue:

Chức năng: xóa tất cả các nút có trong hàng đợi.
Dữ liệu nhập: không.
Dữ liệu xuất: front và tail với giá trị phù hợp.

Các phương pháp cài đặt Queue-ADT

Cũng như stack chúng ta cài đặt hàng đợi theo hai cách là cài đặt kiểu kế tiếp (dùng mảng 1 chiều hoặc dùng mảng vòng) và cài đặt kiểu liên kết (dùng DSLK đơn, vòng, kép, kép+vòng và giống như stack thì cài đặt bằng DSLK kép+vòng là hay nhất).
Để đơn giản và dễ hiểu nhất thì tớ sẽ cài đặt bằng mảng 1 chiều. Minh họa bằng ngôn ngữ C++

const Max = 100;
class queue
{
      private:
       int front,tail; //dau va cuoi hang doi
      int nodes[Max];
   public:
       queue()   // cau tu khoi dong hang doi
      {
           front = 0;
         tail = -1;
      }
      int empty();  // kiem tra hang doi bi rong khong
      int full(); // kiem tra hang doi co bi day chua
      void insert(int x); // them mot nut vao cuoi hang doi
      int remove(); // xoa nut o dau hang doi
      int queuesize(); // xac dinh so nut co trong hang doi
};
int queue::empty()
{
     return ((tail < front) ? true : false);
}
int queue::full()
{
    return ((tail == Max-1) ? true : false);
}
void queue::insert(int x)
{
     if(full())
       cout<<"Hang doi bi day";
   else
        nodes[++tail] = x;
}
int queue::remove()
{
     if(empty())
       cout<<"hang doi bi rong";
   else
       return(nodes[front++]);
}
int queue::queuesize()
{
    return(tail - front + 1);
}

Đã được chỉnh sửa lần cuối bởi iamvtn : 23-11-2007 lúc 11:01 PM.
Trả lời cùng với trích dẫn
  #3  
Cũ 24-11-2007, 11:03 AM
No Avatar
chuonggio_mailaniemdau chuonggio_mailaniemdau là offline
Thành viên mới
 
Ngày gia nhập: 10 2007
Bài viết: 6
Mặc định

Mình có chút thắc mắc:
Giả sử stack có a[0],a[1].......................a[n] phần tử.
Khi bạn gắn: top=-1; có phải nó tương ứng với a[1]?
Mình thấy khi check stack của bạn là: top=max -1; => danh sách đầy.
Nếu mình gắn: top=1; thì khi: top=max; => danh sách đầy???
Giải thích giúp mình nhá

Đã được chỉnh sửa lần cuối bởi iamvtn : 24-11-2007 lúc 01:29 PM.
Trả lời cùng với trích dẫn
  #4  
Cũ 24-11-2007, 01:23 PM
Avatar của iamvtn
iamvtn iamvtn là offline
Free as the wind
 
Ngày gia nhập: 01 2007
Nơi ở: Somewhere I belong
Bài viết: 168
Mặc định

Trích dẫn:
Nguyên bản được gửi bởi chuonggio_mailaniemdau Xem bài viết
Mình có chút thắc mắc:
Giả sử stack có a[0],a[1].......................a[n] phần tử.
Khi bạn gắn: top=-1; có phải nó tương ứng với a[1]?
Mình thấy khi check stack của bạn là: top=max -1; => danh sách đầy.
Nếu mình gắn: top=1; thì khi: top=max; => danh sách đầy???
Giải thích giúp mình nhá.
Thực sự bạn vẫn chưa hiểu về mảng, mảng ở đây số phần tử sẽ bắt đầu = 0, và top ở đây là để chỉ số phần tử đầu tiên trong mảng. Do vậy mình gán top = -1 tức là trường hợp mảng chưa có phần tử nào, và top = 0 tức là phần tử đầu tiên trong mảng và top = Max - 1 = 100 - 1 = 99 mảng đã đầy 100 phần tử. Còn nếu bạn gán top = 1 tức là bạn đã bỏ qua mất phần tử đầu tiên của mảng đó là phần tử a[0] và top = max = 100 thì sẽ bị vượt quá một phần tử của mảng. Nếu bạn khai báo mảng có 100 phần tử thì mảng sẽ bắt đầu từ a[0] cho đến a[99], chắc đến đây bạn hiểu rồi chứ. Tớ nghĩ bạn hãy xem lại lý thuyết về mảng để nắm rõ hơn, rất là cơ bản đấy.

Đã được chỉnh sửa lần cuối bởi iamvtn : 27-11-2007 lúc 10:25 AM.
Trả lời cùng với trích dẫn
  #5  
Cũ 26-11-2007, 06:10 PM
Avatar của iamvtn
iamvtn iamvtn là offline
Free as the wind
 
Ngày gia nhập: 01 2007
Nơi ở: Somewhere I belong
Bài viết: 168
Mặc định

Sử dụng stack để đổi cơ số.


Sử dụng stack để đổi cơ số.

class List;
class Node
{
    private:
    int data;
      Node *next;
   public:
    Node(int d = 0,Node *p = NULL)
    {
        data = d;
        next = p;
      }
      int get()
      {
        return data;
      }
      friend class List;
};
class List
{
    private:
    Node *head;
   public:
    List() {head = NULL;}
      ~List()
      {
        head = NULL;
      }
      int get()
      {
        return head->data;
      }
      void chen_dau(int d)
      {
        Node *p = new Node(d);
         if(head == NULL)
                head=p;
         else
         {
            p->next = head;
            head = p;
         }
      }
      void xoa_dau()
      {
        if(head)
        {
            Node *p = head;
            head = head->next;
            p->next = NULL;
            delete p;
        }
      }
      void chen_cuoi(int d)
      {
        Node *p = new Node(d);
        Node *q = head;
         if(head == NULL)
        head=p;
        else
        {
            while(q->next)
            q = q->next;
            q->next = p;
        }
      }
      void xoa_cuoi()
      {
        if(head)
        if(head->next == NULL)
        {
            delete head;
            head=0;
        }
        else
        {
            Node *p,*q;
            p=head;
            p=p->next;
            while(q->next)
            {
                p = q;
                q = q->next;
            }
            delete q;
            p->next = NULL;
        }
      }
      bool empty()
      {
        if(head == NULL)
            return true;
         else
            return false;
      }
      void hienthi()
      {
        Node *p = head;
            while(p)
        {
            cout<<p->data<<"\t";
            p = p ->next;
        }
      }
};
class stack
{
    private:
        List a;
   public:
    void push(int d)
      {
        a.chen_dau(d);
      }
      int get()
      {
        return a.get();
      }
      void pop()
      {
        a.xoa_dau();
      }
      void hienthi()
      {
         a.hienthi();
      }
      bool empty()
      {
        if(a.empty() == true)
            return true;
         else
            return false;
      }
};

void main()
{
    stack a;
   int so,coso;
   float sodu;
   cout<<"Nhap vao so: ";
   cin>>so;
    cout<<"Co so la bao nhieu (2 or 4 or 8): ";
   cin>>coso;
   while(so != 0)
   {
    sodu = so % coso;
      a.push(sodu);
      so = so / coso;
   }
   cout<<"So vua chuyen la: ";
   for(int i = 0;;i++)
   {
        cout<<a.get();
      a.pop();
      if(a.empty())
      break;
   }
   getch();
}
Trả lời cùng với trích dẫn
  #6  
Cũ 23-09-2008, 11:26 AM
Avatar của trunkthai
trunkthai trunkthai là offline
Thành viên mới
 
Ngày gia nhập: 08 2008
Nơi ở: homeless
Bài viết: 15
Mặc định

Cho em hỏi nếu mình khai báo stack như sau:

class stack
{
          int size;
          int top;
          int* stackPtr;
      public:
          stack(){};
          stack(int s):size(s),top(0){stackPtr = new int [size];}
           ......................
}

thì destructor mình viết hàm inline
~stack(){delete [] stackPtr;}

hay là viết như vầy: (em nghĩ viết như cách này mới đúng)
stack::~stack()
{
            while(! IsEmpty())
            {
                        delete [] stackPtr;
                        top--;
            }
}

Chúc mừng anh zkday lên chức

Đã được chỉnh sửa lần cuối bởi trunkthai : 23-09-2008 lúc 11:57 AM.
Trả lời cùng với trích dẫn
  #7  
Cũ 23-09-2008, 11:58 AM
Avatar của Tab
Tab Tab là offline
Thành viên nhiệt tình
 
Ngày gia nhập: 10 2007
Nơi ở: /root
Bài viết: 316
Mặc định

Đây là stack tớ cài, chắc sẽ giải quyết được vấn đề của cậu :
// stack.h
#ifndef _STACK_H_
#define _STACK_H_

template <class T>
class Stack
{
private:
    T *Item;
    int Size;
    int Top;
public:
    Stack(int s = 1);
    ~Stack();
    void Push(T obj);
    T & Pop();
    T & GetTop() const;
    bool IsEmpty()const;

};

template <class T>
Stack<T>::Stack(int s)
{
    Size = s;
    Item = new T[s];
    Top = -1;
}

template <class T>
Stack<T>::~Stack()
{
    delete [] Item;
}

template <class T>
void Stack<T>::Push(T obj)
{
    if(Top == Size - 1) // Stack đầy
    {
        Size *= 3;
        T *NewItem = new T[Size]; // Mở rộng stack
        for (int i = 0 ; i < Size ; i ++)
        {
            NewItem[i] = Item[i];
        }

        delete [] Item;

        Item = NewItem;
    }
    Item[++Top] = obj;
}

template <class T>
T & Stack<T>::Pop()
{
    return Item[Top--];
}

template <class T>
T & Stack<T>::GetTop()const
{
    return Item[Top];
}

template <class T>
bool Stack<T>::IsEmpty() const
{
    if(Top == -1){
        return true;
    }
    return false;
}


#endif //_STACK_H_

__________________
What you see is never what you get...

Đã được chỉnh sửa lần cuối bởi Tab : 23-09-2008 lúc 12:12 PM.
Trả lời cùng với trích dẫn
  #8  
Cũ 23-09-2008, 12:11 PM
Avatar của trunkthai
trunkthai trunkthai là offline
Thành viên mới
 
Ngày gia nhập: 08 2008
Nơi ở: homeless
Bài viết: 15
Mặc định

Cám on anh void main,giờ mới thấy mình bị điên,con trỏ stack chỉ cấp phat 1 lần lúc khởi động để làm nhiệm vụ truy cập các phtu của stack thôi.
Không hiểu sao mình dám viết destructor thế kia...Cám ơn mấy anh
Trả lời cùng với trích dẫn
  #9  
Cũ 23-09-2008, 12:19 PM
Avatar của rox_rook
rox_rook rox_rook là offline
Power Member
 
Ngày gia nhập: 12 2006
Nơi ở: US
Bài viết: 1,897
Mặc định

Code voidmain() có rất nhiều lỗi logic, code không safe. Ví dụ constructor chẳng hạn.
Cấp phát size = s nhưng nội dung = undefined. -> giả nếu r2 gọi Pop() thì sao ?
Cả pop lẫn top đều phải bắt buộc kiểm tra range.
Hàm push mắc lỗi nghiêm trọng : DANGLING POINTER !
__________________
The best C++ library ever! http://www.boost.org/
Trả lời cùng với trích dẫn
  #10  
Cũ 23-09-2008, 12:25 PM
Avatar của Tab
Tab Tab là offline
Thành viên nhiệt tình
 
Ngày gia nhập: 10 2007
Nơi ở: /root
Bài viết: 316
Mặc định

Tất nhiên , đây là code tớ phác thử , với việc gọi Pop , đúng ra phải kiểm tra Empty , nếu không kiểm tra Empty , giá trị trả về sẽ là 1 giá trị chưa được định nghĩa .
Còn hàm Push, tớ ko hiểu lỗi RR nói , có thể chỉ rõ hơn đc ko ?
__________________
What you see is never what you get...
Trả lời cùng với trích dẫn
Trả lời
Google
 

Bookmarks

Các công cụ đề tài
Các chế độ hiển thị

Các nguyên tắc gửi bài
Bạn không thể gửi đề tài mới
Bạn không thể gửi bài trả lời
Bạn không thể gửi các đính kèm
Bạn không thể chỉnh sửa bài viết của bạn

[IMG] code: On
HTML code: Off

Nhảy tới diễn đàn

Các đề tài tương tự
Đề tài Người bắt đầu đề tài Diễn đàn Các trả lời Bài viết cuối
Xây dựng lớp stack cho ngăn xếp kiểu int hoaxuyenchi Thắc mắc lập trình C/C++/C++0x 9 14-10-2012 09:53 PM
Stack, ngăn xếp - Thiết lập và ứng dụng stack trong C PoPoPoPo Thủ thuật, Tutorials CTDL & Giải thuật 8 15-11-2010 11:24 PM


Toàn bộ thời gian tính theo múi GMT +7. Bây giờ là 03:42 PM.