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指针移动游标
- 增加的与遍历相关函数如下
![](https://img2018.cnblogs.com/blog/1037399/201810/1037399-20181008195704013-1965246238.png)
- 函数原型为
//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 }
小结:
- 单链表的遍历需要在线性时间内完成
- 在单链表的内部定义游标变量(指针),通过游标变量提高效率
- 遍历的函数需要相互依赖,相互的配合
- 封装节点的申请和删除操作有利于增强扩展性