演算法導論之九(10.2不帶哨兵節點和帶哨兵節點的雙向鏈表),10.2哨兵

來源:互聯網
上載者:User

演算法導論之九(10.2不帶哨兵節點和帶哨兵節點的雙向鏈表),10.2哨兵

        不帶哨兵節點的雙向鏈表即一般的雙向鏈表,有一個頭指標指向第一個節點,每個節點有key值和兩個指標next和pre,分別指向前後相鄰的節點,頭結點的pre=NULL,尾節點的next=NULL,比較明了,但是也有麻煩的地方:在做尋找刪除節點等操作的時候,免不了要判斷邊界條件,比如node==NULL等。先來看看這種鏈表的代碼:


/* * 實現沒有哨兵節點的雙向鏈表,需要自己判斷邊界條件 */#include <iostream>using namespace std;class list {struct node {int key;node* next;node* pre;node(int k) :key(k), next(NULL), pre(NULL) {}};public:node* head;int len;list() :head(NULL), len(0) {}~list() {node* tmp1 = head, *tmp2;while (tmp1 != NULL) {tmp2 = tmp1->next;delete tmp1;len--;cout << "len=" << len << endl;tmp1 = tmp2;}}/* * 在頭處插入節點 */void insertHead(int k) {node* n = new node(k);n->next = head;head = n;if (n->next != NULL) {n->next->pre = n;}len++;}/* * 刪除指標指向的節點 */int del(node* n) {if (n == NULL) {return -1;}if (n->pre != NULL) {n->pre->next = n->next;} else {head = n->next;}if (n->next != NULL) {n->next->pre = n->pre;}delete n;len--;return n->key;}/* * 尋找具有某個key值的節點 */node* searchList(int k) {if (len == 0) {return NULL;}node* tmp = head;while (tmp != NULL) {if (tmp->key == k) {break;}tmp = tmp->next;}return tmp;}/* * 遍曆list */void travelList() {node* tmp = head;while (tmp != NULL) {cout << tmp->key << ' ';tmp = tmp->next;}cout << endl;}};int main() {list* l = new list();l->insertHead(5);l->insertHead(4);l->insertHead(3);l->travelList();l->del(l->head->next);l->travelList();delete l;return 0;}

        每次判斷邊界條件,雖然不會從根本上增加時間複雜度,但是對其常數項還是有影響的;而如果使用帶哨兵節點構成的雙向迴圈鏈表,則可以省去這些問題。我們使用一個“啞的”NIL節點來代替之前的head頭指標,NIL節點的key值沒有實際的意義,主要關注它的next和pre,初始的時候,鏈表只有一個NIL節點,NIL.next指向自己,NIL.pre也指向自己。當添加了若干個節點之後,NIL.next指向前端節點,而NIL.pre則指向尾節點;而同樣的,這時前端節點的pre不再是NULL而是指向NIL,尾節點的next也不再是NULL,也是指向NIL。


        這樣的好處在於,我們判斷邊界條件的時候,不需要再判斷是否為空白,尤其在刪除節點的時候,只需要寫兩句即可。但是這樣也帶來一些問題,就是要額外分配空間來儲存NIL節點,如果對於多個比較短的鏈表而言,這樣可能會代碼比較大的冗餘空間。


代碼如下:

/* * 實現帶哨兵是雙向迴圈鏈表 */#include <iostream>using namespace std;class list {struct node {int key;node* next;node* pre;node(int k) :key(k), next(NULL), pre(NULL) {}};//node* head;public:node* nil; //哨兵節點int len;list() :nil(), len(0) {nil = new node(0); //初始化哨兵節點//讓鏈表迴圈起來nil->next = nil;nil->pre = nil;}~list() {//析構的時候要delete掉還存在於list中的節點if (len == 0) {delete nil;return;}node* n1 = nil->next;node* n2 = NULL;while (n1 != NULL && n1 != nil) {n2 = n1->next;delete n1;len--;n1 = n2;}delete nil;}/* * 在頭部插入節點 */void insertHead(int k) {node* n = new node(k);n->next = nil->next;n->pre = nil;nil->next = n;//這一句不要丟了n->next->pre = n;len++;}/* * 刪除節點,這裡刪除的操作只需要寫兩句,比不帶哨兵的鏈表操作要簡潔的多 */void del(node* n) {n->pre->next = n->next;n->next->pre = n->pre;delete n;len--;}node* searchList(int k) {node* tmp = nil->next;//讓nil的key值永遠不可能等於k//nil->key = k + 1;//while (tmp->key != k) {while (tmp != nil && tmp->key != k) {tmp = tmp->next;}if (tmp != nil) {return tmp;} else {return NULL;}}/* * 從next指標方向遍曆鏈表 */void travelClockwise() {node* tmp = nil->next;while (tmp != nil) {cout << tmp->key << ' ';tmp = tmp->next;}cout << endl;}/* * 從pre指標方向遍曆鏈表 */void travelAnticlockwise() {node* tmp = nil->pre;while (tmp != nil) {cout << tmp->key << ' ';tmp = tmp->pre;}cout << endl;}};int main() {list* l = new list();l->insertHead(5);l->insertHead(4);l->insertHead(3);l->travelClockwise();l->del(l->nil->pre);//l->travelClockwise();l->travelAnticlockwise();return 0;}











聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.