優先隊列
——.NET數據結構與算法系列之四
追憶,2013年11月20日
前言
在生活中我們常常會遇到棧和隊列的問題,比如放盤子、取盤子(類似棧)先進后出的集合,排隊(類似隊列)先進先出的集合。這兩種情況在.NET里面已經有相關的類庫Stack和Queue,在這里不再進行討論,有興趣的朋友可以百度一下這方面的資料。在這里主要討論下優先隊列,是在Queue基礎上的擴展。
1.優先隊列
大家所知,隊列是一種先進先出的數據結構。這種行為的效果就是會最先移除結構內最早進入的數據項。然而,對於很多應用程序而言,需要一種可以把具有最高優先級的數據項最先移除的數據結構,即使這個數據項在結構中不是“最早進入的”一個。對於這類應用程序Queue有一種特殊的情況,那就是優先隊列。
許多應用程序在操作中都用到了優先隊列。一個很好的實例就是在計算機操作系統內的進程處理。某些進程可能有高於其他進程的優先級,比如打印機進程就有典型的低優先級。進程(或任務)通常會根據優先級進行編號,Priority(優先級)為0的進程比Priority為20的任務具有更高的優先級。
通常會把存儲在優先隊列中的數據項作為鍵值對來構造,其中關鍵字就是指優先級別,而值則用來識別數據項。例如,可以按照如下形式對一個操作系統進程進行定義:
struct Process
{
int priority;
string name;
}
我們不能把未修改的Queue對象用於優先隊列。DeQueue方法在被調用時只會把隊列中的第一個數據項移除。但是,大家可以從Queue類派生出自己的優先隊列類,同時覆蓋DeQueue方法來實現自己的需求。
我們把這個類稱為PQueue。所有Queue的方法都可以照常使用,同時覆蓋DeQueue方法來移除具有最高優先級的數據項。為了不從隊列前端移除數據項,首先需要把隊列的數據項寫入一個數組。然后遍歷整個數組從而找到具有最高優先級的數據項。最后,根據標記的數據項,就可以不考慮此標記數據項的同時對隊列進行重建。
具體類的代碼如下:
public struct PQItem
{
public int Priority;
public string Name;
}
public class PQueue : Queue
{
public PQueue()
{
}
public override object Dequeue()
{
object[] items;
int min;
items = this.ToArray();
min = ((PQItem)items[0]).Priority;
for (int x = 1; x <= items.GetUpperBound(0); x++)
{
if (((PQItem)items[x]).Priority < min)
{
min = ((PQItem)items[x]).Priority;
}
}
this.Clear();
int tmp;
for (tmp = 0; tmp <= items.GetUpperBound(0); tmp++)
{
if (((PQItem)items[tmp]).Priority == min &&
((PQItem)items[tmp]).Name != "")
this.Enqueue(items[tmp]);
}
return base.Dequeue();
}
}
接下來的代碼說明了PDeque類的一個簡單應用。急診等待室對就診的病人配置了優先級,心臟病突發的病人應該在割傷的病人之前進行治療。下面這個程序模擬了三個幾乎在同一時間進入急診室的病人。分診護士在檢查完每一位病人后會分配給他們一個優先級,同時會把這些病人添加到隊列內。進行治療的第一個病人會通過Dequeue方法從隊列中移除。
public static void PQueueTest()
{
SmartTechnology.PQueue erwait = new SmartTechnology.PQueue();
SmartTechnology.PQItem[] erPatient = new SmartTechnology.PQItem[3];
SmartTechnology.PQItem nextPatien;
erPatient[0].Name = "Joe Smith";
erPatient[0].Priority = 1;
erPatient[1].Name = "Mary Brown";
erPatient[1].Priority = 0;
erPatient[2].Name = "Sam Jones";
erPatient[2].Priority = 3;
for (int x = 0; x <= erPatient.GetUpperBound(0);x++ )
{
erwait.Enqueue(erPatient[x]);
}
nextPatien = (PQItem)erwait.Dequeue();
Console.WriteLine(nextPatien.Name);
}
由於”Mary Brown”擁有高於其他兩位病人的優先級,所以程序的輸出是”Mary Brown”。
小結
學會適當且高效地使用數據結構能使程序更一目了然、易於理解。高級程序員會認識到把程序的數據按照適當的數據結構進行組織會使得數據的處理工作更加簡單。事實上,用數據抽象來思考計算機編程,問題會更容易最先得到解決問題的好的方案。
堆棧和隊列可以用於解決計算機編程方面許多不同類型的問題,特別是諸如解釋器和編譯器這類系統編程領域的問題。
隊列也有許多的應用。操作系統用隊列(通過優先隊列)來對進程進行排序,而且隊列還時常用於模擬現實世界的過程。
源程序下載:DataStructAndAlgorithm.zip
參考書箱:<<數據結構與算法>>