铅笔

在你的害怕中坚持的越多,你就会越自信
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

单链表的遍历与优化

Posted on 2018-10-08 20:00  黑色の铅笔  阅读(2921)  评论(0编辑  收藏  举报
1. 单链表存在的问题
(1). 问题引入
怎么样遍历单链表中的元素?
(2). 原来单链表的遍历
#include <iostream>
#include "linklist.h"
 
using namespace std;
using namespace DTLib;
 
int main()
{
    LinkList<int> l;
 
    for(int i=0;i<6;i++)   //时间复杂度O(n)
    {
        l.insert(0,i);
    }
 
    for(int i=0;i<l.length();i++)//时间复杂度O(n)
    {
     cout<<l.get(i)<<endl;        //时间复杂度O(n)
    }
}

 


 
 
根据事件复杂度分析可知道遍历时的时间复杂度为了O(n2)
时间复杂度太多效率低  所以需要改进
 
2. 设计的思路
(1) 在单链表内部定义一个游标( Node* m_current)
(2) 遍历开始前将游标指向位置为0的数据元素
(3) 获取游标指向的数据元素
(4)  通过节点中的next指针移动游标
 
  • 增加的与遍历相关函数如下

 

 

  • 函数原型为

 //LinkList.h

  1 #ifndef LINKLIST_H
  2 #define LINKLIST_H
  3 #include "List.h"
  4 namespace DataStructureLib
  5 {
  6     template <typename T>
  7 
  8     class LinkList:public List<T>
  9     {
 10     protected:
 11         struct Node{
 12             T value;
 13             Node* next;
 14         };
 15 
 16         mutable Node m_header;//头结点 、mutable为了让get函数中的const属性导致的&m_header(编译器认为是要修改成员变量)mutable就允许const成员函数取地址
 17         int m_length;//链表的长度
 18 
 19         Node* position(int i) const//返回第i和元素的指针
 20         {
 21             Node* ret=&m_header;
 22 
 23             for(int p=0;p<i;p++)
 24             {
 25                 ret=ret->next;
 26             }
 27 
 28             return ret;//元素地址保存在该节点的next指针域中
 29         }
 30         
 31         //游标
 32         int m_step;
 33         Node* m_current ;
 34     public:
 35         LinkList()
 36         {
 37             m_header.next=NULL;
 38             m_length=0;
 39             m_step=1;
 40             m_current=NULL;
 41         }
 42         
 43         bool insert(int index, const T& elem)//思路:1.找到index位置处的元素;2.在该元素尾部insert新元素
 44         {
 45             bool ret=(index<=m_length)&&(index>=0);
 46 
 47             Node* NewNode=new Node ;
 48 
 49             if (ret)
 50             {
 51                 if (NULL!=NewNode)
 52                 {
 53                     NewNode->value=elem;
 54 
 55                     Node* indexNode=position(index);
 56                     NewNode->next=indexNode->next;
 57                     indexNode->next=NewNode;
 58 
 59                     m_length++;
 60                 }
 61                 else{
 62                     throw("has Not enougth memory to insert new element ...");
 63                 }
 64 
 65             }
 66             return ret;
 67         }
 68 
 69         bool remove(int index)
 70         {
 71             bool ret=((index<=m_length)&&(index>=0));
 72 
 73             if (ret)
 74             {
 75                 Node* CurrentNode=position(index);
 76                 Node* toDelNode=CurrentNode->next;
 77                 CurrentNode->next=toDelNode->next;
 78 
 79                 delete toDelNode ;
 80                 m_length--;
 81             }
 82 
 83             return ret;
 84         }
 85         
 86         bool set(int index,const T& e)
 87         {
 88             bool ret=((0<=index)&&(index<=m_length));
 89 
 90             if (ret)
 91             {
 92                 Node* CurrentNode=position(index);
 93                 CurrentNode->next->value=e;
 94             }
 95             
 96             return  ret; 
 97         }
 98 
 99         bool get(int index, T& elem) const
100         {
101             bool ret=((index<=m_length)&&(index>=0));
102 
103             if (ret)
104             {
105                 Node* CurrentNode=position(index);
106                 elem= CurrentNode->next->value;
107             }
108 
109             return ret;
110         }
111 
112         T get(int index)
113         {
114             T ret;
115             if((index<m_length)&&(0<=index))
116             {
117                 Node* CurrentNode=position(index);
118                 ret= CurrentNode->next->value;
119             }
120 
121             return ret; 
122         }
123         int getlength() const
124         {
125             return m_length;
126 
127         }
128 
129         void clear()
130         {
131                                 
132             while (m_header.next)
133             {
134                 Node* toDelNode=m_header.next;
135                 m_header.next=toDelNode->next;
136                 delete toDelNode;
137             }
138             m_length=0;
139         }
140         
141         //寻找e元素所在的位置,
142         //返回值 失败:-1    成功:e元素所在的位置的id
143         int find(T& e)
144         { 
145             int ret = -1;
146             for (int i=0;i<m_length;i++)
147             {
148                 if (e==get(i))
149                 {
150                     ret=i;
151                 }
152             }
153 
154             return ret;
155         }   
156 
157 
158         bool move(int i,int step=1)//将游标定位到目标位置,//i代表目标位置  step游标每次移动的节点的数目
159         {
160             bool ret= (0<=i)&&(i<m_length)&&(step>0);
161 
162             if (ret)
163             {
164                 m_current=position(i)->next;
165                 m_step=step;
166             }
167 
168         return ret;
169 
170         }
171 
172         bool end()//游标有无到达链表尾部
173         {
174             return (m_current==NULL);
175         }
176 
177         T current()//获取游标所指向的数据元素
178         {
179             if(!end())
180             {
181                 return  m_current->value ;
182             }
183             else
184             {
185                 throw("No Value at current position...");
186             }
187         }
188 
189         //移动游标  相当于每次移动的大小m_step
190         bool next()
191         {
192 
193             int i=0;
194 
195             while ((m_step>i)&&(!end()))
196             {
197                 m_current=m_current->next;
198                 i++;
199             }
200 
201             return (i==m_step);
202         }
203         
204         ~LinkList()
205         {
206             clear();
207         }
208 };
209 
210 }
211 #endif

测试:

 1 #include<iostream>
 2 #include "object.h"
 3 #include "SeqList.h"
 4 #include "LinkList.h"
 5 
 6 using namespace std;
 7 using namespace DataStructureLib;
 8 
 9 
10 int main(int argc, char const *argv[])
11 {
12     LinkList<int> l;
13 
14     for(int i=0;i<6;i++)
15     {
16         l.insert(0,i);
17     }
18 
19     for(l.move(0,1);(!l.end());l.next())
20     {
21         cout<<l.current()<<endl;
22     }
23     system("pause"); 
24     return 0;
25 }
小结:
  • 单链表的遍历需要在线性时间内完成
  • 在单链表的内部定义游标变量(指针),通过游标变量提高效率
  • 遍历的函数需要相互依赖,相互的配合
  • 封装节点的申请和删除操作有利于增强扩展性