把以前寫的東西貼在這里方便回故
以前我們建立一個隊列.一開始接口不太友好.后來我們進行了優化.
Queue abc; //聲明隊列結構體 crteate_Queue(abc); //創建隊列 abc.push(int num); //壓入 int abc = abc.pop();//彈出
大致是這樣子的.但是我們發現,這個隊列有一個非常明顯的缺陷.那就是,只能push進int型的變量,如果我們想要壓進去其它類型.甚至是自定義類型.那么,我們就得對這個隊列程序進行大刀闊斧似的改變.幾乎所有的代碼都改了,但是代碼的邏輯卻是一模一樣,讓人"捉急",不甘心,邏輯一模一樣的代碼,每次改變類型,我們需要去修改大部分代碼才能使用,這樣的程序是我們不想要的.所以我們需要一個通用的隊列,它的目標是:
1.我們不需要去修改隊列的代碼.
2.它能push進任何類型
如果在C++,有模板類,可以很容易解決這個問題,但是在C里,我們只好想一個巧妙的辦法來完成這個任務.
首先,我們只考慮隊列,它的數據結構是這樣的:
typedef struct _Node{ struct _Queue * prev; struct _Queue * next; }Node; typedef Node* Node_Pion; //它的指針類型
然后是它的行為:
Node_Pion node_push(Node_Pion tail, Node_Pion node) //給我一個尾指針,一個結點. { if (!node) return NULL; if(tail) tail-next = node; node->prev = tail; tail = node; return tail; } Node_Pion node_pop (Node_Pion head) //給我一個頭指針. { if(head-next) head->next->prev = NULL; head = head->next; return head; }
從上面看出,這里和昨天並無什么 太大的區別.
下面是關鍵..
然后我們對這個隊列進行封裝:
typedef struct _Queue{ Node_Pion HEAD; //它的頭 Node_Pion TAIL; //它的尾 }Queue; typedef Queue* Queue_pion; //它的行為 //構造 Queue_pion ctreate_queue(Queue_pion queue){ if(!queue) queue = (Queue_pion)malloc(sizeof(_Queue)); queue->HEAD = NULL; queue->TAIL = NULL; return queue; } //析構 void delete_queue(Queue_pion queue){ free(queue); } //壓入 void push (Queue_pion queue, void* node){ if((!queue->HEAD) && (!queue->TAIL)) //如果頭尾有一個等於NULL.隊列無效 queue->TAIL = queue->HEAD = node_push(queue->TAIL, (Node_Pion)node); //重新建立隊列 else queue->TAIL = node_push(queue->TAIL, (Node_Pion)node); //給我一個尾指針,一個結點. } //彈出 void* pop (Queue_pion queue){ Node_Pion p = queue->HEAD; queue->HEAD = node_pop(queue->HEAD); return (void*)p; }
這樣,我們在使用時就比較好玩了
比如,我們有一個自定義的類型
struct abc{ int num; int val; };
然后,我們在代碼里,構造一個隊列:
Queue *abc = ctreate_queue(Queue_pion queue); typedef struct _abc{ Node node; //我們在這個自定義結構里的第一個元素,加上我們的結點結構的一個元素. int num; int val; }*abc; 還是起個好用的名字吧.
abc p=(abc)malloc(sizeof(_abc)); // 申請一個新對象
push(bgd,p); //這樣就可以壓入隊列了
pop(bgd) ; //這樣就可以彈出了,更簡單