第30课 - 双向链表的实现

1、双向链表的实现 

            交流中。。。 

        

            单链表的另—个缺陷 

                -单向性 

                        只能从头结点开始高效访问链表中的数据元素 

                -缺陷 

                        如果需要 逆向访问单链表中的数据元素将 极其低效

                


                新的线性表 

                        设计思路: 

                                    在“单链表”的结点中增加指针pre, 

                                    用于指向当前结点的前驱结点。

    

            双向链表的继承层次结构

                

            在有些设计方案中是作为LinList的子类实现的


            DualLinkList的定义 

            


2、编程实验 

双向链表的实现     DualLinkList.h


                                                注意3、4操作的条件


DualLinkList.h

  1. #ifndef DUALLINKLIST_H  
  2. #define DUALLINKLIST_H  
  3.   
  4. #include"List.h"  
  5. #include"Exception.h"  
  6.   
  7. namespace DTLib  
  8. {  
  9.   
  10. template <typename T>  
  11. class DualLinkList : public List<T>  
  12. {  
  13. protected:  
  14.     struct Node : public Object  
  15.     {  
  16.         T value;  
  17.         Node* next;  
  18.         Node* pre;  
  19.     };  
  20.     mutable struct : public Object   
  21.     {  
  22.         char reserved[sizeof(T)];    
  23.         Node* next;  
  24.         Node* pre;  
  25.     }m_header;  
  26.   
  27.     int m_length;  
  28.   
  29.     Node* m_current;  
  30.     int m_step;  
  31.   
  32.     Node* position(int i) const       
  33.     {  
  34.         Node* ret  = reinterpret_cast<Node*>(&m_header);  
  35.   
  36.         for(int p=0;p<i;p++)  
  37.         {  
  38.             ret = ret->next;  
  39.         }  
  40.   
  41.         return ret;  
  42.     }  
  43.   
  44.     virtual Node* create()  
  45.     {  
  46.         return new Node();  
  47.     }  
  48.     virtual void destroy(Node* pn)  
  49.     {  
  50.         delete pn;  
  51.     }  
  52.   
  53. public:  
  54.     DualLinkList()  
  55.     {  
  56.         m_header.next = NULL;  
  57.         m_header.pre = NULL;  
  58.         m_length = 0;  
  59.         m_step = 1;  
  60.         m_current = NULL;  
  61.     }  
  62.     bool insert(int i,const T& e)  
  63.     {  
  64.         bool ret = (0 <= i)&&(i <= m_length);  
  65.   
  66.         if(ret)  
  67.         {  
  68.             Node* node = create();  
  69.   
  70.             if( node )  
  71.             {  
  72.                 Node* current = position(i);  
  73.                 Node* next = current->next;  
  74.   
  75.                 node->value = e;  
  76.   
  77.                 node->next = next;  
  78.                 current->next = node;  
  79.   
  80.                 if( current != reinterpret_cast<Node*>(&m_header) )     
  81.                 {  
  82.                     node->pre = current;  
  83.                 }  
  84.                 else  
  85.                 {  
  86.                     node->pre = NULL;  
  87.                 }  
  88.   
  89.                 if(next != NULL)    //新结点插入最后位置  
  90.                 {  
  91.                     next->pre = node;  
  92.                 }  
  93.   
  94.                 m_length++;  
  95.             }  
  96.             else  
  97.             {  
  98.                 THROW_EXCEPTION(NoEnoughMemoryException,"No memory to insert new element ...");  
  99.             }  
  100.         }  
  101.   
  102.         return ret;  
  103.     }  
  104.     bool insert(const T& e)  
  105.     {  
  106.         return insert(m_length,e);  
  107.     }  
  108.     bool remove(int i)  
  109.     {  
  110.         bool ret = (0 <= i)&&(i < m_length);  
  111.   
  112.         if(ret)  
  113.         {  
  114.             Node* current = position(i);  
  115.   
  116.             Node* toDel = current->next;  
  117.             Node* next = toDel->next;  
  118.   
  119.             if(m_current == toDel)  
  120.             {  
  121.                 m_current = next;    //游标指向下一个数据元素即可  
  122.             }  
  123.   
  124.             current->next = next;  
  125.   
  126.             if(next != NULL)  
  127.               next->pre = toDel->pre;  
  128.   
  129.             m_length--;  
  130.   
  131.             destroy(toDel);  
  132.   
  133.         }  
  134.   
  135.         return ret;  
  136.     }  
  137.     bool set(int i,const T& e)  
  138.     {  
  139.         bool ret = (0 <= i)&&(i < m_length);  
  140.   
  141.         if(ret)  
  142.         {  
  143.             position(i)->next->value = e;  
  144.         }  
  145.   
  146.         return ret;  
  147.     }  
  148.     virtual T get(int i) const  
  149.     {  
  150.         T ret;  
  151.   
  152.         if(get(i,ret))  
  153.         {  
  154.             return ret;  
  155.         }  
  156.         else  
  157.         {  
  158.             THROW_EXCEPTION(IndexOutOfBoundsExpception,"Invalid parameter i to get element ...");  
  159.         }  
  160.   
  161.         return ret;  
  162.     }  
  163.     bool get(int i,T& e) const  
  164.     {  
  165.         bool ret = (0 <= i)&&(i < m_length);  
  166.   
  167.         if(ret)  
  168.         {  
  169.             e = position(i)->next->value;   //position 为 const 成员函数  
  170.         }  
  171.   
  172.         return ret;  
  173.     }  
  174.     int find(const T& e) const  
  175.     {  
  176.         int ret = -1;  
  177.         int i = 0;  
  178.   
  179.         Node* node = m_header.next;  
  180.   
  181.         while( node )  
  182.         {  
  183.             if(node->value == e)  
  184.             {  
  185.                 ret = i;  
  186.                 break;  
  187.             }  
  188.             else  
  189.             {  
  190.                 node = node->next;  
  191.   
  192.                 i++;  
  193.             }  
  194.         }  
  195.   
  196.         return ret;  
  197.     }  
  198.     int length() const  
  199.     {  
  200.         return m_length;  
  201.     }  
  202.   
  203.     void clear()    //O(n)  
  204.     {  
  205.         while(m_length > 0)  
  206.         {  
  207.             remove(0);  
  208.         }  
  209.     }  
  210.     virtual bool move(int i,int step = 1)  
  211.     {  
  212.         bool ret = (0 <= i)&&(i < m_length)&&(step > 0);  
  213.   
  214.         if(ret)  
  215.         {  
  216.             m_current = position(i)->next;  
  217.             m_step = step;  
  218.         }  
  219.   
  220.         return ret;  
  221.     }  
  222.     virtual bool end()  
  223.     {  
  224.         return ( m_current == NULL);  
  225.     }  
  226.     virtual T current()  
  227.     {  
  228.         if(!end())    
  229.         {  
  230.             return m_current->value;  
  231.         }  
  232.         else  
  233.         {  
  234.             THROW_EXCEPTION(InvalidParameterException,"No value at current position ...");  
  235.         }  
  236.     }  
  237.     virtual bool next()  
  238.     {  
  239.         int i = 0;  
  240.         while((i < m_step) && !end())  
  241.         {  
  242.             m_current = m_current->next;  
  243.             i++;  
  244.         }  
  245.   
  246.         return (i == m_step);  
  247.     }  
  248.     virtual bool pre()  
  249.     {  
  250.         int i = 0;  
  251.         while((i < m_step) && !end())  
  252.         {  
  253.             m_current = m_current->pre;  
  254.             i++;  
  255.         }  
  256.   
  257.         return (i == m_step);  
  258.     }  
  259.   
  260.     ~DualLinkList()  
  261.     {  
  262.         clear();      
  263.     }  
  264. };  
  265. }  
  266. #endif // DUALLINKLIST_H  


main.cpp

#include <iostream>
#include"DualLinkList.h"
 
 
using namespace std;
using namespace DTLib;
 
 
 
 
int main()
{
    DualLinkList<int> d1;
 
 
    for(int i=0;i<5;i++)
    {
        d1.insert(0,i);
        d1.insert(0,5);
    }
    for(d1.move(0);!d1.end();d1.next())
    {
        cout<<d1.current()<<" ";
    }
 
 
    cout<<endl;
 
 
    for(d1.move(d1.length()-1);!d1.end();d1.pre())  //逆序访问 O(1)
    {
        cout<<d1.current()<<" ";
    }
    cout<<endl;
 
 
    d1.move(d1.length()-1);
 
 
    while(!d1.end())
    {
        if(d1.current() == 5)
        {
            cout<<d1.current()<<" ";
            d1.remove(d1.find(d1.current()));
        }
        else
        {
            d1.pre();
        }
    }
 
 
    cout<<endl;
 
 
    for(d1.move(d1.length()-1);!d1.end();d1.pre())  
    {
        cout<<d1.current()<<" ";
    }
    cout<<endl;
 
 
 
 
    return 0;
}
 
 
 
 


                


3、小结 

            双向链表是为了弥补单链表的缺陷而重新设计的 

            在概念上,双向链表不是单链表,没有继承关系 

            双向链表中的游标能够直接访问当前结点的前驱和后继 

            双向链表是线性表概念的最终实现( 更贴近理论上的线性表


4、深度思考 

            开放性问题 

                    DualLinkListLinkList中存在很多完全—样的代 

                    码,如何进行重构降低代码的冗余性?冗余代码的 

                    出现是否意味着DualLinkListLinkList之间应该 

                    是继承关系? 


5、扩展练习 

            双向链表的子类 




猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/80266191