C++ 數(shù)據(jù)結(jié)構(gòu)之鏈表

鏈表

一在扰、 何為鏈表

引用維基百科的介紹, 鏈表(Linked list)是一種常見的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu), 是一種線性表, 但是并不會(huì)按照線性的順序存儲(chǔ)結(jié)構(gòu),是一種"在物理空間上非連續(xù)袋励、非順序的存儲(chǔ)結(jié)構(gòu)"挚瘟。

由于不必須按順序存儲(chǔ)抄瑟,鏈表在插入的時(shí)候可以達(dá)到O(1)的復(fù)雜度摩梧,比另一種線性表順序表快得多普气,但是查找一個(gè)節(jié)點(diǎn)或者訪問特定編號(hào)的節(jié)點(diǎn)則需要O(n)的時(shí)間唐断,而順序表相應(yīng)的時(shí)間復(fù)雜度分別是O(logn)和O(1)麸祷。

鏈表通常由一連串節(jié)點(diǎn)組成撮抓,每個(gè)節(jié)點(diǎn)包含:

- 鏈域:   它的值是線性表的上一個(gè)/下一個(gè)元素的位置,即地址摇锋。
- 數(shù)據(jù)域: 它的值是存儲(chǔ)的相應(yīng)實(shí)例數(shù)據(jù)的值丹拯。

二、鏈表的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  1. 使用鏈表結(jié)構(gòu)可以克服數(shù)組鏈表需要預(yù)先知道數(shù)據(jù)大小的缺點(diǎn)荸恕,鏈表結(jié)構(gòu)可以充分利用計(jì)算機(jī)內(nèi)存空間乖酬,實(shí)現(xiàn)靈活的內(nèi)存動(dòng)態(tài)管理。
  2. 相比數(shù)組結(jié)構(gòu)融求,對(duì)于元素的插入和刪除操作來說咬像,鏈表的效率要比數(shù)組高,因?yàn)槊總€(gè)節(jié)點(diǎn)都有鏈域存儲(chǔ)指向下一個(gè)節(jié)點(diǎn)的指針,因此進(jìn)行插入和刪除的操作時(shí)不需要頻繁的移動(dòng)其他的元素县昂,只需要修改對(duì)應(yīng)位置附近節(jié)點(diǎn)的鏈域的值即可肮柜。

缺點(diǎn)

  1. 查詢鏈表只能通過指針順序訪問,效率相對(duì)低下倒彰,查詢可能需要O(n)的時(shí)間復(fù)雜度审洞。
  2. 因?yàn)殒湵淼拿總€(gè)節(jié)點(diǎn)都含有鏈域,所占用的空間較多待讳。

三芒澜、單鏈表的實(shí)現(xiàn)(C++)

  • 定義節(jié)點(diǎn)的結(jié)構(gòu)
template<class T>
struct ListNode
{
  T m_tElement;          // 數(shù)據(jù)域
  ListNode<T>* m_pNext;  // 鏈域
  // 構(gòu)造函數(shù)
  ListNode(){}
  ListNode(const T& theElement) {this->m_tElement = theElement;}
  ListNode(const T& theElement, ListNode<T>* theNext)
  {
    this->m_tElement = theElement;
    this->m_pNext = theNext;
  }
}
  • 定義鏈表類
template<class T>
class SingleList
{
public:
    // 構(gòu)造函數(shù)與析構(gòu)函數(shù)
    SingleList();
    SingleList(const SingleList<T>& theList);
    ~SingleList();
    
    // 類方法 
    bool empty() const {return m_iLength == 0;}      // 判斷鏈表是否為空
    int size() const {return m_iLength;}             // 返回鏈表長度
    int indexOf(const T& theElement) const;          
    T& get(int theIndex) const;
    void insert(int theIndex, const T& theElement);
    void delete(int theIndex);
    void update(int theIndex, const T& theElement);
    
private:
    void checkIndex(theIndex);  // 確認(rèn)是否索引值是否合法
    int m_iLength;              // 鏈表的長度
    ListNode<T>* m_pFirstNode;  // 鏈表的頭節(jié)點(diǎn)
}
  • 構(gòu)造函數(shù)的實(shí)現(xiàn)
// 無參構(gòu)造函數(shù)
template<class T>
SingleList<T>::SingleList()
{
  m_pFirstNode = NULL;
  m_iLength = 0;
}
// 復(fù)制構(gòu)造函數(shù)
template<class T>
SingleList<T>::SingleList(const SingleList<T>& theList)
{
  m_iLength = theList.m_iLength;
  // 判斷源鏈表是否為空鏈表
  if(m_iLength == 0)
  {
    m_pFirstNode = NULL;
    return;
  }
 
  ListNode<T>* otherNode = theList.m_pFirstNode;
  m_pFirstNode = new ListNode<T>(otherNode->m_tElement);
  ListNode<T>* thisNode = m_pFirstNode;
  otherNode = otherNode->m_pNext;
  
  while (otherNode != NULL)
  { 
    // 當(dāng)源鏈表后續(xù)還有節(jié)點(diǎn)時(shí),復(fù)制鏈表剩下的其他節(jié)點(diǎn)
    thisNode->m_pNext = new ListNode<T>(otherNode->m_tElement);
    thisNode = thisNode->m_pNext;
    otherNode = otherNode->m_pNext;
  }
  thisNode->next = NULL;
}
  • 析構(gòu)函數(shù)的實(shí)現(xiàn)
template<class T>
SingleList<T>::~SingleList()
{
  while (m_pFirstNode != NULL)
  {
    ListNode<T>* tempNode = m_pFirstNode;
    delete m_pFirstNode;
    m_pFirstNode = tempNode;
  }
}
  • 類方法的實(shí)現(xiàn)

    int indexOf(const T& theElement) const

// 返回指定元素的索引值
template<class T>
int SingleList<T>::indexOf(const T& theElement) const
{
  ListNode<T>* currNode = m_pFirstNode;
  int index = 0;
  while (currNode != NULL && currNode->m_tElement != theElement)
  {
    currNode = currNode->m_pNext;
    ++index;
  }
  if (currNode == NULL)
  {
    return -1;
  }
  if (currNode != NULL)
    return index;
}

? T& get(int theIndex) const

// 返回指定索引的元素
template<class T>
T& SingleList<T>::get(int theIndex) const
{
  checkIndex(theIndex);
  ListNode<T>* currNode = m_pFirstNode;
  // 找到索引值對(duì)應(yīng)的元素
  for(int i = 0; i < theIndex; ++i)
    currNode = currNode->m_pNext;
  // 返回元素的值
  return currNode->m_tElement;
}

? void insert(int theIndex, T& theElement)

// 在指定位置插入元素
template<class T>
void SingleList<T>::insert(int theIndex, const T& theElement)
{ // 判斷索引值是否合法
  checkIndex(theIndex);
  if (theIndex == 0)
  {
    m_pFirstNode = new ListNode<T>(theElement, m_pFirstNode)
  }
  if (theIndex > 0)
  {
     ListNode<T>* currNode = m_pFirstNode;
     // 因?yàn)橐谥付ㄎ恢貌迦朐? 因此去找指定位置的前一個(gè)元素
     for (int i = 0; i < theIndex - 1; ++i)
        currNode = currNode->m_pNext;
     ListNode<T>* newNode = new ListNode<T>(theElement, currNode->m_pNext);
  }
  ++m_iLength;
}

? void delete(int theIndex)

// 刪除指定位置的元素
template<class T>
void SingleList<T>::delete(int theIndex)
{
  checkIndex(theIndex);
  ListNode<T>* targetNode;
  if (theIndex == 0)
  {
    targetNode = m_pFirstNode;
    m_pFirstNode = m_pFirstNode->m_pNext;
  }
  if (theIndex > 0)
  {
    ListNode<T>* prevNode = m_pFirstNode;
    for (int i = 0; i < theIndex - 1; ++i) 
      prevNode = prevNode->m_pNext;
    targetNode = prevNode->m_pNext;
    prevNode->m_pNext = targetNode->m_pNext;
  }
  delete targetNode;
  --m_iLength;
}

? void update(int theIndex, const T& theElement)

// 修改指定位置元素的值
template<class T>
void SingleList<T>::update(int theIndex, const T& theElement)
{
  // 判斷索引值是否合法
  checkIndex(theIndex);
  // 
  if (theIndex == 0)
  {
    m_pFirstNode->m_tElement = theElement;
    return ;
  }
  
  ListNode<T>* currNode = m_pFirstNode;
  for (int i = 0; i < theIndex; ++i)
    currNode = currNode->m_pNext;
  currNode->m_tElement = theElement;
}

? void checkIndex(int theIndex)

// 檢查索引值是否合法
template<class T>
void SingleList<T>::checkIndex(int theIndex)
{
  if (theIndex < 0 || theIndex > m_iLength - 1)
    std::cout << "Error Index Value" << std::endl;
}

四创淡、結(jié)語

這是我第一次做類似的學(xué)習(xí)筆記痴晦,借鑒了網(wǎng)上許多的博客以及書籍的資料和內(nèi)容,在這里做個(gè)記錄琳彩,若是有錯(cuò)誤或不恰當(dāng)之處誊酌,希望各路大神能不吝賜教,指點(diǎn)小弟不足之處露乏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碧浊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子施无,更是在濱河造成了極大的恐慌,老刑警劉巖必孤,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猾骡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡敷搪,警方通過查閱死者的電腦和手機(jī)兴想,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赡勘,“玉大人嫂便,你說我怎么就攤上這事≌⒂耄” “怎么了毙替?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長践樱。 經(jīng)常有香客問我厂画,道長,這世上最難降的妖魔是什么拷邢? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任袱院,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忽洛。我一直安慰自己腻惠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布欲虚。 她就那樣靜靜地躺著集灌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苍在。 梳的紋絲不亂的頭發(fā)上绝页,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音寂恬,去河邊找鬼续誉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛初肉,可吹牛的內(nèi)容都是我干的酷鸦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼牙咏,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼臼隔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起妄壶,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤摔握,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后丁寄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氨淌,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年伊磺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盛正。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屑埋,死狀恐怖豪筝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摘能,我是刑警寧澤续崖,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站团搞,受9級(jí)特大地震影響袜刷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莺丑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一著蟹、第九天 我趴在偏房一處隱蔽的房頂上張望墩蔓。 院中可真熱鬧,春花似錦萧豆、人聲如沸奸披。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阵面。三九已至,卻和暖如春洪鸭,著一層夾襖步出監(jiān)牢的瞬間样刷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工览爵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留置鼻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓蜓竹,卻偏偏與公主長得像箕母,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子俱济,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容