資料結構學習(C++)——雙向連結串列 (轉)

amyz發表於2007-11-07
資料結構學習(C++)——雙向連結串列 (轉)[@more@]

原書這部分內容很多,至少相對於迴圈連結串列是很多。相信當你把單連結串列的指標域搞清楚後,這部分應該難不倒你。現在我的問題是,能不能從單連結串列派生出雙向連結串列?:namespace prefix = o ns = "urn:schemas--com::office" />

你可以有幾種做法:

一種就是先定義一個雙鏈節點——但是,它的名字必須叫Node,這是沒辦法的事;不然你就只好複製一份單連結串列的實現,把其中的Node全都替換成你的雙鏈節點名字,但是這就不叫繼承了。

另一種做法就是先定義一種結構例如這樣的:

template class newtype

{

public:

Type data;

Node *link;

}

當你派生雙向連結串列時,這樣寫template class lList : public List >,注意連續的兩個“>”之間要有空格。或者根本不定義這樣的結構,直接拿Node型別來做,例如我下面給出的。但是,請注意要完成“==”的過載,否則,你又要重寫Find,並且其他的某些操作也不方便。

在開始完成你的從單連結串列派生出來的雙向連結串列之前,要在單連結串列這個基類中新增修改當前指標和當前前驅指標的介面,如下所示:

protected:

  void Put(Node *p)//儘量不用,雙向連結串列將使用這個完成向前移動

  {

    current = p;

  }

 

  void PutPrior(Node *p)//儘量不用,原因同上

  {

  prior = p;

  }

因為這個介面很危險,而且幾乎用不到,所以我在前面並沒有給出,但要完成雙向連結串列最“傑出”的優點——向前移動當前指標,必須要使用。另外說的是,我從前也從來沒計劃從單連結串列派生雙連結串列,下面你將看到,這個過程很讓人煩人,甚至不如重寫一個來的省事,也不是很好,這種費力不討好的事做它有什麼意思呢?的確,我也覺得我在鑽牛角尖。(別拿雞蛋丟我)

定義和實現

#ifndef DblList_H

#define DblList_H

 

#include "List.h"

 

template class DblList : public List< Node >

{

public:

  Type *Get()

  {

  if (pGet() != NULL) return &pGet()->data.data;

  else return NULL;

  }

 

  Type *Next()

  {

    pNext();

  return Get();

  }

 

  Type *Prior()

  {

  if (pGetPrior != NULL)

  {

    Put(pGetPrior());

    PutPrior( (Node< Node >*)pGet()->data.link);

    return Get();

  }

  return NULL;

  }

 

  void Insert(const Type &value)

  {

    Node newdata(value, (Node*)pGet());

  List< Node >::Insert(newdata);

  if (pGetNext()->link != NULL)

pGetNext()->link->data.link = (Node*)pGetNext();

  }

 

  BOOL Remove()

  {

  if (List< Node >::Remove())

  {

    pGet()->data.link = (Node*)pGetPrior();

    return TURE;

  }

  return FALSE;

  }

 

};

 

#endif

【說明】只完成了最重要的Insert和Remove函式和最具特點的Prior()函式,其他的沒有重新實現。所以,你在這裡使用單連結串列的其他方法,我不保證一定正確。並且,這裡的指標型別轉換依賴於實現,我也不能肯定其他的編譯器編譯出來也能正確。對於讓不讓Prior返回頭節點的data,我考慮再三,反正用First();Get();這樣的組合也能返回,所以就不在乎他了,所以要是用Prior遍歷直到返回NULL,就會將頭節點的data輸出來了。

【補充】至於雙向迴圈連結串列,也可以從這個雙向連結串列派生(仿照派生迴圈連結串列的方法);或者從迴圈連結串列派生(仿照派生雙向連結串列的方法),就不一一舉例了(再這樣下去,我就真鬧心的要吐血了)。至此,可以得出一個結論,連結串列的各種結構都是能從單連結串列派生出來的。換句話說,單連結串列是根本所在,如果研究透了單連結串列,各種鏈式結構都不難。

一小段測試

void DblListTest_int()

{

  DblList a;

  for (int i = 10; i > 1; i--) a.Insert(i);

  for (i = 10; i > 1; i--) cout << *a.Next() << " ";

  a.First();

  cout << endl;

  cout << *a.Next() << endl;

  cout << *a.Next() << endl;

  cout << *a.Next() << endl;

  cout << *a.Next() << endl;

  a.Remove();

  cout << *a.Get() << endl;

  cout << *a.Prior() << endl;

  cout << *a.Prior() << endl;

  cout << *a.Prior() << endl;

}

【後記】從我對雙向連結串列不負責任的實現來看,我並不想這麼來實現雙向連結串列,我只是嘗試怎樣最大限度的利用已有的類來實現這種型別。實踐證明,不如重寫一個。別人看起來也好看一些,自己寫起來也不用這樣鬧心。不過,這個過程讓我對函式的和返回的理解又更深了一步。如果你能第一次就寫對這裡的Insert函式,相信你一定對C++有一定的感觸了。我也覺得,只有做一些創新,才能最已經很成熟的東西更深入的瞭解。比如,這些資料結構,在C++的標準庫(STL)中都可以直接拿來用,我們為什麼還辛辛苦苦的寫,結果還不如人家原來的好。為了學習,這就是理由,這也是一切看起來很笨的事發生的理由。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-981175/,如需轉載,請註明出處,否則將追究法律責任。

相關文章