یک آموزش عمیق در مورد Deque یا صف دو طرفه در C++. آموزش توضیح می دهد که Deque چیست، عملیات پایه، C++ و amp; پیاده سازی جاوا و برنامه های کاربردی:
صف دو پایان یا به سادگی "Deque" یک نسخه کلی از Queue است.
تفاوت بین Queue و Deque در این است که از FIFO پیروی نمی کند. رویکرد (اولین ورودی، اول بیرون). دومین ویژگی Deque این است که ما می توانیم عناصر را از دو قسمت جلو یا عقب حذف کنیم. به صورت زیر طبقه بندی شود:
Input-restricted Deque: در input-restricted، حذف را می توان از هر دو انتها انجام داد، اما درج را می توان فقط در انتهای پشتی انجام داد. queue.
Output-restricted Deque: در صف با محدودیت خروجی، درج از هر دو انتها قابل انجام است اما حذف فقط در یک انتها یعنی انتهای جلوی صف انجام می شود.
ما همچنین میتوانیم پشتهها و صفها را با استفاده از deque پیادهسازی کنیم.
عملیات پایه Deque
عملیات زیر عملیاتهای اساسی است که میتوان روی deque انجام داد.
- درج جلو: یک مورد را در جلوی دک درج یا اضافه کنید.
- insertLast: یک مورد را درج کنید یا اضافه کنید پشت صفحه.
- deleteFront: حذف یا حذف مورد از جلوی صف.
- حذف آخرین: حذف یا حذف مورد از پشتصف.
- getFront: آیتم جلویی را در deque بازیابی می کند.
- getLast: آخرین مورد را در صف بازیابی می کند.
- isEmpty: بررسی میکند که صفحه خالی است یا خیر.
- isFull: بررسی میکند که آیا deque پر است یا خیر.
Deque Illustration
یک دک خالی به صورت زیر نمایش داده می شود:
بعد، عنصر 1 را در جلو وارد می کنیم.
اکنون، عنصر 3 را در عقب قرار می دهیم.
بعد، عنصر 5 را به جلو اضافه می کنیم و هنگامی که افزایش می یابد، نقاط جلو به 4.
سپس، عناصر 7 را در عقب و 9 را در جلو قرار می دهیم. Deque مانند شکل زیر خواهد بود.
بعد، اجازه دهید یک عنصر را از جلو حذف کنیم.
بنابراین، می بینیم که وقتی عناصر در جلو وارد می شوند، موقعیت جلو کاهش می یابد در حالی که با حذف یک عنصر افزایش می یابد. برای قسمت عقب، موقعیت برای درج افزایش و برای حذف کاهش می یابد .
Deque Implementation
C++ Deque Implementation
ما می توانیم یک Deque را پیاده سازی کنیم. در C++ با استفاده از آرایه ها و همچنین لیست پیوندی. جدای از این، کتابخانه قالب استاندارد (STL) دارای یک کلاس "deque" است که تمام توابع این ساختار داده را پیاده سازی می کند.
اجرای آرایه deque در زیر آورده شده است. از آنجایی که این یک صف دو طرفه است، از آرایه های دایره ای برای آن استفاده کرده ایمپیاده سازی.
#includeusing namespace std; #define MAX_size 10 // Maximum size of array or Dequeue // Deque class class Deque { int array[MAX_size]; int front; int rear; int size; public : Deque(int size) { front = -1; rear = 0; this->size = size; } // Operations on Deque: void insertfront(int key); void insertrear(int key); void deletefront(); void deleterear(); int getFront(); int getRear(); // Check if Deque is full bool isFull() return ((front == 0 && rear == size-1) // Check if Deque is empty bool isEmpty(){ return (front == -1); } }; // Insert an element at front of the deque void Deque::insertfront(int key) { if (isFull()) { cout "Overflow!!\n" endl; return; } // If queue is initially empty,set front=rear=0; start of deque if (front == -1) { front = 0; rear = 0; } else if (front == 0) // front is first position of queue front = size - 1 ; else // decrement front 1 position front = front-1; array[front] = key ; // insert current element into Deque } // insert element at the rear end of deque void Deque ::insertrear(int key) { if (isFull()) { cout " Overflow!!\n " endl; return; } // If queue is initially empty,set front=rear=0; start of deque if (front == -1) { front = 0; rear = 0; } else if (rear == size-1) // rear is at last position of queue rear = 0; else // increment rear by 1 position rear = rear+1; array[rear] = key ; // insert current element into Deque } // Delete element at front of Deque void Deque ::deletefront() { if (isEmpty()) { cout "Queue Underflow!!\n" endl; return ; } // Deque has only one element if (front == rear) { front = -1; rear = -1; } else // back to initial position if (front == size -1) front = 0; else // remove current front value from Deque;increment front by 1 front = front+1; } // Delete element at rear end of Deque void Deque::deleterear() { if (isEmpty()) { cout " Underflow!!\n" endl ; return ; } // Deque has only one element if (front == rear) { front = -1; rear = -1; } else if (rear == 0) rear = size-1; else rear = rear-1; } // retrieve front element of Deque int Deque::getFront() { if (isEmpty()) { cout " Underflow!!\n" endl; return -1 ; } return array[front]; } // retrieve rear element of Deque int Deque::getRear() { if(isEmpty() || rear 0) { cout " Underflow!!\n" endl; return -1 ; } return array[rear]; } //main program int main() { Deque dq(5); cout "Insert element 1 at rear end \n"; dq.insertrear(1); cout "insert element 3 at rear end \n"; dq.insertrear(3); cout "rear element of deque " " " dq.getRear() endl; dq.deleterear(); cout "After deleterear, rear = " dq.getRear() endl; cout "inserting element 5 at front end \n"; dq.insertfront(5); cout "front element of deque " " " dq.getFront() endl; dq.deletefront(); cout "After deletefront, front = " dq.getFront() endl; return 0; }
خروجی:
درج عنصر 1 در انتهای عقب
درج عنصر در انتهای پشت
عنصر پشت از deque 3
پس از deleterear، rear =
درج عنصر 5 در قسمت جلویی
عنصر جلوی deque 5
بعد از deleterear، front =
اجرای Java Deque
اینترفیس deque در جاوا، "java.util.Deque" از رابط "java.util.Queue" مشتق شده است. Deque را می توان به عنوان یک صف (اولین ورودی، اول خروج) یا پشته (آخرین ورود، اولین خروج) استفاده کرد. این پیاده سازی ها سریعتر از لیست پیوندی کار می کنند.
در زیر سلسله مراتب رابط Deque در جاوا ارائه شده است.
ما باید چند نکته را در مورد رابط Deque در جاوا به خاطر بسپاریم:
- پیاده سازی از نظر رشته ای ایمن نیست زیرا همگام سازی خارجی وجود ندارد.
- Deque این کار را انجام نمی دهد. پشتیبانی از همزمانی توسط رشتههای متعدد.
- Deque که با استفاده از آرایهها پیادهسازی میشود، اجازه استفاده از عناصر NULL را نمیدهد.
- آرایهها با ظرفیت بدون محدودیت و پشتیبانی از آرایه قابل تغییر اندازه مجاز هستند طبق نیاز رشد کنند. این دو ویژگی مهم هستند.
روش های مختلفی که توسط رابط Deque پشتیبانی می شوند در زیر آمده است:
خیر | روش | توضیح |
---|---|---|
1 | add(element) | یک عنصر را به دم اضافه می کند. |
2 | addFirst(element) | یک عنصر را بهhead/front. |
3 | addLast(element) | یک عنصر را به tail/rear اضافه می کند. |
4 | offer(element) | یک عنصر را به دم اضافه می کند. یک مقدار بولی برای نشان دادن موفقیت آمیز بودن درج برمی گرداند. |
5 | offerFirst(element) | یک عنصر را به head اضافه می کند. یک مقدار بولی برای نشان دادن موفقیت آمیز بودن درج برمی گرداند. |
6 | offerLast(element) | یک عنصر را به دم اضافه می کند. یک مقدار بولی برای نشان دادن موفقیت آمیز بودن درج برمی گرداند. |
7 | iterator() | یک تکرار کننده برای deque برمی گرداند. |
8 | descendingIterator() | تکراری را برمیگرداند که ترتیب معکوس برای این deque دارد. |
9 | push(element) | یک عنصر را به سر deque اضافه می کند. |
10 | pop(element) | یک عنصر را از سر deque حذف می کند و آن را برمی گرداند. |
11 | removeFirst() | عنصر را در سر deque. |
12 | removeLast() | عنصر را در دم deque حذف می کند. |
13 | poll() | اولین عنصر deque را بازیابی و حذف می کند (نماینده رئیس deque). اگر deque خالی باشد، NULL را برمی گرداند. |
14 | pollFirst() | اولین عنصر این deque را بازیابی و حذف می کند. اگر این deque باشد، null برمیگرداندخالی. |
15 | pollLast() | آخرین عنصر این deque را بازیابی و حذف می کند. اگر این deque خالی باشد، null را برمیگرداند. |
16 | peek() | هد (اولین عنصر deque) صف ارائهشده را بازیابی میکند. توسط این دکه; اگر این deque خالی باشد، null را برمیگرداند. توجه: این عملیات عنصر را حذف نمیکند. |
17 | peekFirst() | اولین عنصر این دک را بازیابی می کند. اگر این deque خالی باشد، null را برمیگرداند. توجه: این عملیات عنصر را حذف نمیکند. |
18 | peekLast() | آخرین عنصر این deque را بازیابی میکند، یا اگر این deque خالی باشد، null را برمیگرداند. توجه: این عملیات عنصر را حذف نمیکند. |
پیاده سازی جاوا زیر عملیات مختلفی را که در بالا مورد بحث قرار گرفت نشان می دهد.
import java.util.*; class Main { public static void main(String[] args) { Dequedeque = new LinkedList (); // We can add elements to the queue in various ways deque.add(1); // add to tail deque.addFirst(3); deque.addLast(5); deque.push(7); //add to head deque.offer(9); deque.offerFirst(11); deque.offerLast(13); System.out.println("The deque : " + deque + "\n"); // Iterate through the queue elements. System.out.println("Standard Iterator"); Iterator iterator = deque.iterator(); while (iterator.hasNext()) System.out.print(" " + iterator.next()); // Reverse order iterator Iterator reverse = deque.descendingIterator(); System.out.println("\nReverse Iterator"); while (reverse.hasNext()) System.out.print(" " + reverse.next()); // Peek returns the head, without deleting // it from the deque System.out.println("\n\nPeek " + deque.peek()); System.out.println("After peek: " + deque); // Pop returns the head, and removes it from // the deque System.out.println("\nPop " + deque.pop()); System.out.println("After pop: " + deque); // We can check if a specific element exists // in the deque System.out.println("\nContains element 3?: " + deque.contains(3)); // We can remove the first / last element. deque.removeFirst(); deque.removeLast(); System.out.println("Deque after removing " + "first and last elements: " + deque); } }
خروجی:
Deque: [11، 7، 3، 1، 5، 9، 13]
Iterator استاندارد
11 7 3 1 5 9 13
Reverse Iterator
13 9 5 1 3 7 1
Peek 11
بعد از نگاه کردن: [11، 7، 3، 1، 5، 9، 13]
پاپ 11
بعد پاپ: [7، 3، 1، 5، 9، 13]
شامل عنصر 3 است؟: true
Deque پس از حذف اولین و آخرین عناصر: [3، 1، 5، 9]
در برنامه فوق از رابط Deque جاوا استفاده کرده ایم و یک deque از عناصر عدد صحیح تعریف کرده ایم. سپس عملیات مختلفی را بر روی این دک انجام دادیم و خروجی حاصل از این عملیات می باشدنمایش داده می شود.
برنامه ها
Deque را می توان در برخی از برنامه های زیر استفاده کرد.
#1) الگوریتم زمان بندی: یک الگوریتم زمانبندی، «الگوریتم زمانبندی A-steal» زمانبندی کار را برای پردازندههای مختلف در سیستم چند پردازندهای پیادهسازی میکند. این پیاده سازی از deque استفاده می کند و پردازنده اولین عنصر را از deque برای اجرا می گیرد.
#2) Undo List Of Activities: در برنامه های نرم افزاری، اقدامات زیادی داریم. یکی «لغو» است. زمانی که چندین بار عملیات واگرد را انجام دادیم، همه این اقدامات در یک لیست ذخیره می شوند. این لیست به عنوان یک دک نگهداری می شود تا بتوانیم به راحتی ورودی ها را از هر انتهایی اضافه یا حذف کنیم.
#3) پس از مدتی ورودی ها را حذف کنید: برنامه ها تازه می شوند ورودیهای فهرست خود مانند برنامههایی که ورودیهای سهام را فهرست میکنند و غیره. این برنامهها پس از مدتی ورودیها را حذف میکنند و همچنین ورودیهای جدیدی را وارد میکنند. این کار با استفاده از یک Deque انجام می شود.
نتیجه
Deque یک صف دو سر است که به ما امکان می دهد عناصر را از هر دو انتهای صف، یعنی جلو و عقب، اضافه یا حذف کنیم. Deque را می توان با استفاده از آرایه ها یا لیست های پیوندی پیاده سازی کرد. با این حال، ما همچنین یک کلاس استاندارد Template Library (STL) داریم که عملیات های مختلف Deque را پیاده سازی می کند.
در جاوا، ما یک رابط Deque داریم که از رابط صف برای پیاده سازی Deque به ارث می رسد. جدا از عملیات استاندارد پایه Deque، این رابط از انواع مختلفی پشتیبانی می کندسایر عملیاتهایی که میتوان روی Deque انجام داد.
Deque معمولاً برای برنامههایی استفاده میشود که نیاز به افزودن/حذف عناصر از هر دو طرف دارند. همچنین بیشتر در زمانبندی پردازندهها در سیستمهای چند پردازندهای استفاده میشود.