• 第二十四课 单链表的遍历与优化


    问题:

    如何遍历单链表中的每一个元素?

    示例:

     在头部插入元素时,时间复杂度是O(n)。 获取元素时,时间复杂度是O(n*n),因为内层定位位置时有一个O(n)复杂度。

    从理论上来说遍历一个单链表,只需要线性的时间就够了。

    设计思路:

    提供一组相关的遍历函数,遍历时使用这些函数来操作:

     

    move函数的i参数为目标位置,step参数为每次移动的节点数。

    end用来判断当前的游标是否到达了单链表的尾部。

    current返回当前游标指向的数据元素。

    next移动游标,移动的次数根据move中的step的值来决定。

    遍历时,这四个函数必须配合使用才能得到最大效率。

     改进LinkList.h文件中的函数:

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

    第27、28行我们添加了两个成员变量,第185-226行添加了遍历需要的函数。

    测试程序如下:

     1 #include <iostream>
     2 #include "LinkList.h"
     3 
     4 
     5 using namespace std;
     6 using namespace DTLib;
     7 
     8 
     9 int main()
    10 {
    11     LinkList<int> list;
    12 
    13     for(int i = 0; i<5; i++)
    14     {
    15         list.insert(0,i);
    16     }
    17 
    18     //遍历时必须先调用move函数
    19     for(list.move(0); !list.end(); list.next())
    20     {
    21         cout << list.current() << endl;
    22     }
    23 
    24     return 0;
    25 }

    遍历list时必须先调用move函数,指定位置和步进值step,step是给next函数用的,例如:step为5,则每次调用next函数就会向后移动5个元素。

    结果如下:

    这时的遍历操作时间复杂度是O(n)。

    步进值为2时,结果如下:

    单链表内部封装:

    程序改进:

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

    调用new生成Node的地方我们全换成了create函数,调用delete销毁Node的地方我们全换成了destroy函数。

    问题:

    封装这两个函数的意义是什么?

    小结:

  • 相关阅读:
    FDR校正
    PHP base64 编码转化图片并进行指定路径的保存和上传处理(转自https://cloud.tencent.com/developer/article/1333877)
    google网页评测工具
    链接类型:预加载
    鼠标经过时显示、隐藏提示
    thinkphp5导入excel数据
    JS消息窗口滚动到底部
    datatable分页使用箭头
    Mysql基础
    php-MD5/sha1
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9650726.html
Copyright © 2020-2023  润新知