資料結構面試之二——雙向鏈表表、迴圈鏈表、有序鏈表的常見操作

來源:互聯網
上載者:User
資料結構面試之二——雙向鏈表表、迴圈鏈表、有序鏈表的常見操作

題註:《面試寶典》有相關習題,但思路相對不清晰,排版有錯誤,作者對此參考相關書籍和自己觀點進行了重寫,供大家參考。

二、雙向鏈表

雙向鏈表的建立是在單鏈表的基礎上,多了一個指向前驅的指標back。其他的操作類似,注意點就是在雙向鏈表的操作,尤其插入、刪除操作中需要修改兩個指標的指向,一個是back指標,一個是next指標。

1.雙向鏈表的構建【前面插入】

構建雙向鏈表注意點:1)修改first指標(頭指標)的指向。2)修改back、next指標。

//反向表頭插入,從前面插入...

template<typename Type>nodeType<Type>*doublyLinkedList<Type>::buildListBackward(){       nodeType<Type> *newNode;        int num;       cout << " Enter a list of integer end with -999." << endl;       cin >> num;        while(num != -999)       {              //..add              newNode = new nodeType<Type>;              newNode->info = num;              newNode->next = NULL;              newNode->back = NULL;                           if(first == NULL)              {                     first = newNode;              }              else              {                     newNode->next = first;                     first->back = newNode;                     first = newNode;              }               cin >> num;       }       return first;}

2.雙向鏈表的插入節點【此處考慮插入後保證有序,直接插入排序】

節點的插入同單鏈表,依然需要考慮多種因素。分以下幾類:

1)雙向鏈表為空白,“提示資訊”並返回。

2)雙向鏈表非空,待插入節點的元素值小於first節點,需要修改first指標。

3)雙向鏈表非空,待插入節點的元素值為鏈表中間的節點,需修改back、next指向。

4)雙向鏈表非空,待插入節點在最末尾節點以後,修改最末節點的指標。

 //雙向不迴圈鏈表template<typename Type>voiddoublyLinkedList<Type>::insertNode(const Type& insertItem)  //new{nodeType<Type> *current;nodeType<Type> *trailCurrent;nodeType<Type> *newNode;bool found = false; newNode = new nodeType<Type>;newNode->info = insertItem;newNode->next = NULL;newNode->back = NULL; //case 1: 空表if(first == NULL){        first = newNode;}else{        current = first;        while( current != NULL)        {               if( current->info >= insertItem )               {                      found = true;                      break;               }               else               {                      trailCurrent = current;                      current = current->next;               }        }         //case 2: 第一個節點        if(current == first)        {               current->next = newNode;               newNode->back = current;        }        else        {               //case 3: 中間節點               if(current != NULL)               {                      newNode->next = trailCurrent->next;                      current->back = newNode;                      trailCurrent->next = newNode;                      newNode->back = trailCurrent;               }               else  //case 4:最後一個節點前               {                      trailCurrent->next = newNode;                      newNode->back = trailCurrent;               }//end case 4        }}}

3.雙向鏈表的刪除節點

同樣需要考慮以下幾點:

1) 鏈表為空白,“提示資訊”並返回。

2) 鏈表非空,尋找刪除的元素在鏈表是否存在。是的話,found=true;否的話,found=false。

3) 如果沒有找到包含尋找元素的節點,“錯誤提示”並返回。

4) 如果找到,主要節點位置。如果是前端節點或末尾節點主要修改first指標,及節點的back、next指向;如果不是前端節點或者末尾節點就是中間節點,主要back、next的指向,完成插入。

template<typename Type>void doublyLinkedList<Type>::deleteNode(constType& deleteItem)   //new{  nodeType<Type> *current = new nodeType<Type>;  nodeType<Type> *trailCurrent;  bool found = false;          //case 1: 空表  if(first == NULL)  {         cout << "The List is NULL!" << endl;         exit(1);  }  else  {         current = first;         while( current != NULL)         {                if( current->info == deleteItem )                {                       found = true;                       break;                }                else                {                       trailCurrent = current;                       current = current->next;                }         }          if(found)         {                //case 2: 第一個節點                if(current == first)                {                       first = current->next;                       delete current;                }                else                {                       //case 3: 中間節點                       if(current != NULL)                       {                              if(current->next != NULL)  //case3.1:要刪除的是中間節點.                              {                                     trailCurrent->next =current->next;                                     current->next->back = trailCurrent;                                     delete current;                              }                              else                              {                                     trailCurrent->next = NULL;//case3.2:要刪除的為最後一個節點.                                     delete current;                              }                       }                               }// end else         }// end if         else         {                cout << "The elem " <<deleteItem << " is not Exist in the List!" << endl;//case 4: 鏈表中無此節點.         }  }//end else}//end

三、迴圈鏈表

       迴圈鏈表能保障從每一個節點出發都能檢索鏈表。即:last指標的指向不再為空白,而是指向了first(頭結點)。

       迴圈鏈表在構建鏈表、尋找元素、插入、刪除、操作中要注意修改末尾節點指標的指向,保證鏈表的迴圈。

1.      前插式構建迴圈鏈表

【思路】:每次在first指標前面插入節點;插入每個節點後注意修改last->link的指向。

template<typename Type>void cycleList<Type>::bulidCycListBackward() //前插構造迴圈鏈表.{        Type newItem;        while(cin >> newItem, newItem != -999)        {               nodeType<Type>* newNode = newnodeType<Type>;               newNode->info = newItem;               newNode->link = NULL;                if(first == NULL)               {                      first = newNode;                      last = newNode;                      first->link = first;                      last->link = first;               }               else               {                      newNode->link = first;                      last->link = newNode;                      first = newNode;               }        }        cout << "輸入完畢!" << endl;}

2.      迴圈鏈表插入元素[後插入]

【思路】:同構造迴圈鏈表,每次在last指標後面插入節點;插入每個節點後注意修改last->link的指向。

//只在last末尾插入template<typename Type>voidcycleList<Type>::insertCycList(const Type& newItem){nodeType<Type> *newNode = new nodeType<Type>;newNode->info = newItem;newNode->link = NULL; if(first == NULL)        //鏈表為空白...{        first = newNode;        last = newNode;        first->link = first;        last->link = first;}else                   //鏈表非空...{        last->link = newNode;        newNode->link = first;        last = newNode;}cout << newItem << "was inserted!" <<endl;}

3.      刪除迴圈鏈表節點

考慮到是否為空白鏈表、刪除元素在鏈表中不存在、及節點存在(節點的位置可能為共分頭、中間、尾),所以分為以下5種情況分別處理。:

//case1:鏈表為空白。//case2:鏈表非空,刪除節點為前端節點。//case3:鏈表非空,刪除節點為尾節點。//case4:鏈表非空,刪除節點為中間節點。//case5:鏈表非空,不存在=deleteItem的節點。template<typename Type>voidcycleList<Type>::delCycList(const Type& deleteItem){nodeType<Type> *current = new nodeType<Type>;nodeType<Type> *trailCurrent = new nodeType<Type>;nodeType<Type> *temp ;bool found = false; if( first == NULL ){        cout << "The List is Empty!" << endl;//case1        return;}if( first->info == deleteItem )      //case2{        temp = new nodeType<Type>;        temp = first;        first = first->link;        last->link = first;        cout << "The node has" << deleteItem<< " was deleted! " << endl;        delete temp;        return;}else                                             //cas3,case4.需要尋找後定位。{        current = first->link;        while( !found && current != first)        {               if( current->info == deleteItem )               {                      found = true;                      break;               }               else               {                      trailCurrent = current;                      current = current->link;               }        }// end while         if(found)        {                   temp = new nodeType<Type>;               if(current == last)                        //case3               {                      temp = last;                      trailCurrent->link = last->link;       //last->link = first                      last = trailCurrent;               }               else               {                      temp = current;                     trailCurrent->link= current->link;               }               cout << "The Elem : " <<deleteItem << " was deleted! " << endl;               delete temp;        }        else        {               cout << "The Elem : " <<deleteItem << " was not Exist in the List! " << endl;        }}//end else}

四、有序鏈表

注意:此處有序鏈表無非是在之前的一、單鏈表的操作的基礎上,在插入元素的時候,按順序插入,考慮的排序。

為了體現有序的特點,特通過遞迴實現了有序鏈表的逆序列印。關於有序鏈表或者鏈表的非遞迴實現,可以通過棧實現。下一節會分析並實現。

1.      有序鏈表的插入

考慮以下三種情況:

1) 當前鏈表為空白;

2) 當前鏈表非空,要插入的元素值小於頭結點的元素值;

3) 當前鏈表非空,要插入的元素值大於頭結點的元素值,可以考慮找到第一個大於其的元素則停止搜尋,插入其前即可。

template<typename Type>void orderedLinkedListType<Type>::insertNode(constType& newItem){nodeType<Type>* current;nodeType<Type>* trailCurrent;nodeType<Type>* newNode; bool found = false; newNode = new nodeType<Type>;newNode->info = newItem;newNode->link = NULL; if(first == NULL)                           //case1:鏈表為空白.{        first = newNode;        last = first;}else{        current = first;                             while( !found && current != NULL)       //迴圈尋找        {               if(current->info >= newItem)               {                      found = true;                      break;               }              else               {                      trailCurrent = current;                      current = current->link;               }        }//end while         //first 特殊處理..        if(current == first)                //case2:新插入的元素小於first節點的元素值..        {               newNode->link = first;                        first = newNode;        }        else //其他..        {               newNode->link = current;       //case3:新插入的節點在非first位置               trailCurrent->link = newNode;        }}//end else}

2.      遞迴實現有序鏈表的逆序列印

template<typename Type>voidorderedLinkedListType<Type>::printListReverse() const   //逆序列印.{     reversePrint(first);     cout << endl;} //遞迴實現單鏈表的逆序列印.template<typename Type>voidorderedLinkedListType<Type>::reversePrint(nodeType<Type>* current)const  //逆序列印{if(current != NULL){        reversePrint(current->link);        cout << current->info << "\t";}}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.