1、單鏈表遍歷優化
遍歷單鏈表中的每個一數據元素
LinkList<int> list;
for(int i = 0; i < 5; i++) // O(n)
{
list.insert(0, i); // O(1), 頭部插入,不涉及循環
}
// 這里的遍歷方法效率很低
for(int i = 0; i < list.length(); i++) // O(n^2)
{
cout << list.get(i) << endl; // O(n)
}
遍歷鏈表的時間復雜度不是線性的,插入元素是線性,遍歷就不是了。
不能以線性的時間復雜度完成單鏈表的遍歷
新的需求:為單鏈表提供新的方法,在線性時間內完成遍歷
設計思路(游標)
- 在單鏈表的內部定義一個游標
Node* m_current
- 遍歷開始前將游標指向位置為0的數據元素
- 獲取游標指向的數據元素
- 通過結點中的
next
指針移動游標
提供一組遍歷相關的函數,以線性的時間復雜度遍歷鏈表
遍歷函數原型設計
bool move(int i, int step = 1);
bool end();
T current();
bool next(); // 移動次數根據step的值來確定
// i 目標位置,step 游標每次移動結點的數目
bool move(int i, int step = 1)
{
bool ret = ((i >= 0) && (i < m_length) && (step > 0));
if(ret)
{
// 將游標定位到目標位置i的地方
m_current = position(i)->next;
m_step = step;
}
return ret;
}
bool end()
{
return (m_current == NULL);
}
T current()
{
// 返回游標指向的位置的元素值
//if(m_current != NULL)
if(!end())
{
return m_current->value;
}
else
{
THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
}
}
bool next()
{
int i = 0;
while((i<m_step) && !end())
{
m_current = m_current->next;
i++;
}
// i的值和m_step的值是一樣的,就表示移動成功
return (i == m_step);
}
// 新的遍歷使用方法
for(list.move(0); !list.end(); list.next()) // O(n)
{
cout << list.current() << endl;
}
2、單鏈表內部的一次封裝
virtual Node* creat()
{
return new Node();
}
virtual void destory(Node* pn)
{
delete pn;
}
3、小結
單鏈表的遍歷需要在線性時間內完成
在單鏈表內部定義游標變量,通過游標變量提高效率
遍歷相關的成員函數是相互依賴,相互配合的關系
封裝結點的申請和刪除操作更有利於增強擴展性