• 线性表的链式存储——单链表的遍历与优化


    1,如何遍历单链表中的每一个数据元素?

           1,当前单链表遍历方法:

                 

                  1,插入的时间复杂度为 O(n),而遍历的时间复杂度为 O(n*n);

                   

    2,遗憾的事实:

           1,不能以线性的时间复杂度完成单链表的遍历;

       新的需求:

           1,为单链表提供新的方法,在线性时间内完成遍历;

    3,设计思路(游标):

           1,在单链表内部定义一个游标(Node* m_current);

           2,遍历开始前将游标指向位置为 0 的数据元素;

           3,获取游标指向的数据元素;

           4,通过结点中的 next 指针移动游标;

       (5),从程序的角度来看,从链表的第 0 个元素一直遍历到最后一个元素,一个 next 指针就够了;

          

    4,设计思路(游标):

           1,提供一组遍历相关的函数,以线性的时间复杂度遍历链表;

                  1,move(),将游标定位到目标位置;

                  2,next(),移动游标;

                  3,current(),获取游标所指向的数据元素;

                  4,end(),获取是否达到尾部(是否为空);

                 

    5,遍历函数原型设计:

           1,bool move(int i, int step = 1);

           2,bool end();

           3,T current();

           4,bool next();

    6,单链表的遍历实现:

     1 /* 以下四个函数move(),end(),next(),current()是为了将遍历输出函数时间复杂度由O(n*n)降为O(n);其中 move() 函数时间复杂度为 i,其后三个函数在 for() 循环中加起来的时间复杂度为才为 O(n),很经典 */
     2 
     3     virtual bool move(int i, int step = 1)  // 从第 i 个位置移动,每次移动 1 个//位置; O(n)
     4     {
     5         bool ret = ( (0<= i) && (i<m_length) && (0<step));
     6 
     7         if( ret )
     8         {
     9             m_current = position(i)->next;   // 定位到节点i,不是第  i 个节点,//所以要加上next,这里时间复杂度严格来说是 i,配合着后面的 next() 函数的移动,//则最终的时间复杂度才是 n;
    10             m_step = step;    // 将每次要移动的值传进来
    11         }
    12         return ret;
    13    }
    14 
    15     virtual bool end()     // 判断当前的游标是否结束
    16     {
    17         return (m_current == NULL);    // 这里不可写成赋值了
    18    }
    19 
    20     virtual T current()   // 获取游标当前位置的值
    21     {
    22         if( !end() ) // m_current != NULL ==> !end(),这里是判断当前指针的有效性;
    23         {
    24             return m_current->value;
    25         }
    26         else
    27         {
    28             THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
    29         }
    30    }
    31 
    32     virtual bool next()   // 移动游标
    33     {
    34         int i = 0;
    35 
    36         while( (i<m_step) && (!end()) )  // 这里的 !end() 是为了判m_step 步幅是否//会将指针指向空,所以在 move() 不用判断 step 的小于范围;
    37         {
    38                 m_current = m_current->next;
    39                 i++;
    40         }
    41 
    42         return (i == m_step);
    43    }

    7,单链表内部的一次封装:

          

           1,这样的封装是因为面向对象里面的主导思想有封装,所以采纳这样的封装;

           2,保护的函数,因为是内部的;

                 

    8,小结:

           1,单链表的遍历需要在线性时间内完成;

           2,在单链表内部定义游标变量,通过游标变量提高效率;

           3,遍历相关的成员函数是相互依赖、相互配合的关系;

           4,封装结点的申请和删除操作更有利于增强扩展性(见后续静态单链表的实现);

  • 相关阅读:
    LQB201803乘积尾零
    最大公约数
    快速幂运算
    二分法查找原理
    递归-24点
    递归-爬楼梯
    递归-中项表达式求解
    IDEA的安装基本使用
    SSM和开源框架 ------面试指导
    JDK 8 新特性
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10921915.html
Copyright © 2020-2023  润新知