数据结构面试之二——双向链表表、循环链表、有序链表的常见操作

来源:互联网 发布:剑灵地狱之歌捏脸数据 编辑:程序博客网 时间:2024/06/06 08:23

数据结构面试之二——双向链表表、循环链表、有序链表的常见操作

题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。

二、双向链表

双向链表的建立是在单链表的基础上,多了一个指向前驱的指针back。其他的操作类似,注意点就是在双向链表的操作,尤其插入、删除操作中需要修改两个指针的指向,一个是back指针,一个是next指针。

1.双向链表的构建【前面插入】

构建双向链表注意点:1)修改first指针(头指针)的指向。2)修改back、next指针。

//反向表头插入,从前面插入...

[cpp] view plaincopy
  1. template<typename Type>  
  2. nodeType<Type>*doublyLinkedList<Type>::buildListBackward()  
  3. {  
  4.        nodeType<Type> *newNode;  
  5.    
  6.        int num;  
  7.        cout << " Enter a list of integer end with -999." << endl;  
  8.        cin >> num;  
  9.    
  10.        while(num != -999)  
  11.        {  
  12.               //..add  
  13.               newNode = new nodeType<Type>;  
  14.               newNode->info = num;  
  15.               newNode->next = NULL;  
  16.               newNode->back = NULL;  
  17.                
  18.               if(first == NULL)  
  19.               {  
  20.                      first = newNode;  
  21.               }  
  22.               else  
  23.               {  
  24.                      newNode->next = first;  
  25.                      first->back = newNode;  
  26.                      first = newNode;  
  27.               }  
  28.    
  29.               cin >> num;  
  30.        }  
  31.        return first;  
  32. }  

2.双向链表的插入节点【此处考虑插入后保证有序,直接插入排序】

节点的插入同单链表,依然需要考虑多种因素。分以下几类:

1)双向链表为空,“提示信息”并返回。

2)双向链表非空,待插入节点的元素值小于first节点,需要修改first指针。

3)双向链表非空,待插入节点的元素值为链表中间的节点,需修改back、next指向。

4)双向链表非空,待插入节点在最末尾节点以后,修改最末节点的指针。

[cpp] view plaincopy
  1.    
  2. //双向不循环链表  
  3. template<typename Type>  
  4. voiddoublyLinkedList<Type>::insertNode(const Type& insertItem)  //new  
  5. {  
  6. nodeType<Type> *current;  
  7. nodeType<Type> *trailCurrent;  
  8. nodeType<Type> *newNode;  
  9. bool found = false;  
  10.    
  11. newNode = new nodeType<Type>;  
  12. newNode->info = insertItem;  
  13. newNode->next = NULL;  
  14. newNode->back = NULL;  
  15.    
  16. //case 1: 空表  
  17. if(first == NULL)  
  18. {  
  19.         first = newNode;  
  20. }  
  21. else  
  22. {  
  23.         current = first;  
  24.         while( current != NULL)  
  25.         {  
  26.                if( current->info >= insertItem )  
  27.                {  
  28.                       found = true;  
  29.                       break;  
  30.                }  
  31.                else  
  32.                {  
  33.                       trailCurrent = current;  
  34.                       current = current->next;  
  35.                }  
  36.         }  
  37.    
  38.         //case 2: 第一个节点  
  39.         if(current == first)  
  40.         {  
  41.                current->next = newNode;  
  42.                newNode->back = current;  
  43.         }  
  44.         else  
  45.         {  
  46.                //case 3: 中间节点  
  47.                if(current != NULL)  
  48.                {  
  49.                       newNode->next = trailCurrent->next;  
  50.                       current->back = newNode;  
  51.                       trailCurrent->next = newNode;  
  52.                       newNode->back = trailCurrent;  
  53.                }  
  54.                else  //case 4:最后一个节点前  
  55.                {  
  56.                       trailCurrent->next = newNode;  
  57.                       newNode->back = trailCurrent;  
  58.                }//end case 4  
  59.         }  
  60. }  
  61. }  

3.双向链表的删除节点

同样需要考虑以下几点:

1) 链表为空,“提示信息”并返回。

2) 链表非空,查找删除的元素在链表是否存在。是的话,found=true;否的话,found=false。

3) 如果没有找到包含查找元素的节点,“错误提示”并返回。

4) 如果找到,主要节点位置。如果是头节点或末尾节点主要修改first指针,及节点的back、next指向;如果不是头节点或者末尾节点就是中间节点,主要back、next的指向,完成插入。

[cpp] view plaincopy
  1. template<typename Type>  
  2. void doublyLinkedList<Type>::deleteNode(constType& deleteItem)   //new  
  3. {  
  4.   nodeType<Type> *current = new nodeType<Type>;  
  5.   nodeType<Type> *trailCurrent;  
  6.   bool found = false;  
  7.           
  8.   //case 1: 空表  
  9.   if(first == NULL)  
  10.   {  
  11.          cout << "The List is NULL!" << endl;  
  12.          exit(1);  
  13.   }  
  14.   else  
  15.   {  
  16.          current = first;  
  17.          while( current != NULL)  
  18.          {  
  19.                 if( current->info == deleteItem )  
  20.                 {  
  21.                        found = true;  
  22.                        break;  
  23.                 }  
  24.                 else  
  25.                 {  
  26.                        trailCurrent = current;  
  27.                        current = current->next;  
  28.                 }  
  29.          }  
  30.    
  31.          if(found)  
  32.          {  
  33.                 //case 2: 第一个节点  
  34.                 if(current == first)  
  35.                 {  
  36.                        first = current->next;  
  37.                        delete current;  
  38.                 }  
  39.                 else  
  40.                 {  
  41.                        //case 3: 中间节点  
  42.                        if(current != NULL)  
  43.                        {  
  44.                               if(current->next != NULL)  //case3.1:要删除的是中间节点.  
  45.                               {  
  46.                                      trailCurrent->next =current->next;  
  47.                                      current->next->back = trailCurrent;  
  48.                                      delete current;  
  49.                               }  
  50.                               else  
  51.                               {  
  52.                                      trailCurrent->next = NULL;//case3.2:要删除的为最后一个节点.  
  53.                                      delete current;  
  54.                               }  
  55.                        }  
  56.                  
  57.                 }// end else  
  58.          }// end if  
  59.          else  
  60.          {  
  61.                 cout << "The elem " <<deleteItem << " is not Exist in the List!" << endl;//case 4: 链表中无此节点.  
  62.          }  
  63.   }//end else  
  64. }//end  

三、循环链表

       循环链表能保障从每一个节点出发都能检索链表。即:last指针的指向不再为空,而是指向了first(头结点)。

       循环链表在构建链表、查找元素、插入、删除、操作中要注意修改末尾节点指针的指向,保证链表的循环。

1.      前插式构建循环链表

【思路】:每次在first指针前面插入节点;插入每个节点后注意修改last->link的指向。

[cpp] view plaincopy
  1. template<typename Type>  
  2. void cycleList<Type>::bulidCycListBackward() //前插构造循环链表.  
  3. {  
  4.         Type newItem;  
  5.         while(cin >> newItem, newItem != -999)  
  6.         {  
  7.                nodeType<Type>* newNode = newnodeType<Type>;  
  8.                newNode->info = newItem;  
  9.                newNode->link = NULL;  
  10.    
  11.                if(first == NULL)  
  12.                {  
  13.                       first = newNode;  
  14.                       last = newNode;  
  15.                       first->link = first;  
  16.                       last->link = first;  
  17.                }  
  18.                else  
  19.                {  
  20.                       newNode->link = first;  
  21.                       last->link = newNode;  
  22.                       first = newNode;  
  23.                }  
  24.         }  
  25.         cout << "输入完毕!" << endl;  
  26. }  

2.      循环链表插入元素[后插入]

【思路】:同构造循环链表,每次在last指针后面插入节点;插入每个节点后注意修改last->link的指向。

[cpp] view plaincopy
  1. //只在last末尾插入  
  2. template<typename Type>  
  3. voidcycleList<Type>::insertCycList(const Type& newItem)  
  4. {  
  5. nodeType<Type> *newNode = new nodeType<Type>;  
  6. newNode->info = newItem;  
  7. newNode->link = NULL;  
  8.    
  9. if(first == NULL)        //链表为空...  
  10. {  
  11.         first = newNode;  
  12.         last = newNode;  
  13.         first->link = first;  
  14.         last->link = first;  
  15. }  
  16. else                   //链表非空...  
  17. {  
  18.         last->link = newNode;  
  19.         newNode->link = first;  
  20.         last = newNode;  
  21. }  
  22. cout << newItem << "was inserted!" <<endl;  
  23. }  

3.      删除循环链表节点

考虑到是否为空链表、删除元素在链表中不存在、及节点存在(节点的位置可能为共分头、中间、尾),所以分为以下5种情况分别处理。:

[cpp] view plaincopy
  1. //case1:链表为空。  
  2. //case2:链表非空,删除节点为头节点。  
  3. //case3:链表非空,删除节点为尾节点。  
  4. //case4:链表非空,删除节点为中间节点。  
  5. //case5:链表非空,不存在=deleteItem的节点。  
  6. template<typename Type>  
  7. voidcycleList<Type>::delCycList(const Type& deleteItem)  
  8. {  
  9. nodeType<Type> *current = new nodeType<Type>;  
  10. nodeType<Type> *trailCurrent = new nodeType<Type>;  
  11. nodeType<Type> *temp ;  
  12. bool found = false;  
  13.    
  14. if( first == NULL )  
  15. {  
  16.         cout << "The List is Empty!" << endl;//case1  
  17.         return;  
  18. }  
  19. if( first->info == deleteItem )      //case2  
  20. {  
  21.         temp = new nodeType<Type>;  
  22.         temp = first;  
  23.         first = first->link;  
  24.         last->link = first;  
  25.         cout << "The node has" << deleteItem<< " was deleted! " << endl;  
  26.         delete temp;  
  27.         return;  
  28. }  
  29. else                                             //cas3,case4.需要查找后定位。  
  30. {  
  31.         current = first->link;  
  32.         while( !found && current != first)  
  33.         {  
  34.                if( current->info == deleteItem )  
  35.                {  
  36.                       found = true;  
  37.                       break;  
  38.                }  
  39.                else  
  40.                {  
  41.                       trailCurrent = current;  
  42.                       current = current->link;  
  43.                }  
  44.         }// end while  
  45.    
  46.         if(found)  
  47.         {      
  48.                temp = new nodeType<Type>;  
  49.                if(current == last)                        //case3  
  50.                {  
  51.                       temp = last;  
  52.                       trailCurrent->link = last->link;       //last->link = first  
  53.                       last = trailCurrent;  
  54.                }  
  55.                else  
  56.                {  
  57.                       temp = current;  
  58.                      trailCurrent->link= current->link;  
  59.                }  
  60.                cout << "The Elem : " <<deleteItem << " was deleted! " << endl;  
  61.                delete temp;  
  62.         }  
  63.         else  
  64.         {  
  65.                cout << "The Elem : " <<deleteItem << " was not Exist in the List! " << endl;  
  66.         }  
  67. }//end else  
  68. }  

四、有序链表

注意:此处有序链表无非是在之前的一、单链表的操作的基础上,在插入元素的时候,按顺序插入,考虑的排序。

为了体现有序的特点,特通过递归实现了有序链表的逆序打印。关于有序链表或者链表的非递归实现,可以通过栈实现。下一节会分析并实现。

1.      有序链表的插入

考虑以下三种情况:

1) 当前链表为空;

2) 当前链表非空,要插入的元素值小于头结点的元素值;

3) 当前链表非空,要插入的元素值大于头结点的元素值,可以考虑找到第一个大于其的元素则停止搜索,插入其前即可。

[cpp] view plaincopy
  1. template<typename Type>  
  2. void orderedLinkedListType<Type>::insertNode(constType& newItem)  
  3. {  
  4. nodeType<Type>* current;  
  5. nodeType<Type>* trailCurrent;  
  6. nodeType<Type>* newNode;  
  7.    
  8. bool found = false;  
  9.    
  10. newNode = new nodeType<Type>;  
  11. newNode->info = newItem;  
  12. newNode->link = NULL;  
  13.    
  14. if(first == NULL)                           //case1:链表为空.  
  15. {  
  16.         first = newNode;  
  17.         last = first;  
  18. }  
  19. else  
  20. {  
  21.         current = first;                       
  22.         while( !found && current != NULL)       //循环查找  
  23.         {  
  24.                if(current->info >= newItem)  
  25.                {  
  26.                       found = true;  
  27.                       break;  
  28.                }  
  29.               else  
  30.                {  
  31.                       trailCurrent = current;  
  32.                       current = current->link;  
  33.                }  
  34.         }//end while  
  35.    
  36.         //first 特殊处理..  
  37.         if(current == first)                //case2:新插入的元素小于first节点的元素值..  
  38.         {  
  39.                newNode->link = first;           
  40.                first = newNode;  
  41.         }  
  42.         else //其他..  
  43.         {  
  44.                newNode->link = current;       //case3:新插入的节点在非first位置  
  45.                trailCurrent->link = newNode;  
  46.         }  
  47. }//end else  
  48. }  

2.      递归实现有序链表的逆序打印

[cpp] view plaincopy
  1. template<typename Type>  
  2. voidorderedLinkedListType<Type>::printListReverse() const   //逆序打印.  
  3. {  
  4.      reversePrint(first);  
  5.      cout << endl;  
  6. }  
  7.    
  8. //递归实现单链表的逆序打印.  
  9. template<typename Type>  
  10. voidorderedLinkedListType<Type>::reversePrint(nodeType<Type>* current)const  //逆序打印  
  11. {  
  12. if(current != NULL)  
  13. {  
  14.         reversePrint(current->link);  
  15.         cout << current->info << "\t";  
  16. }  
  17. }  
0 0
原创粉丝点击