原文:https://www.cnblogs.com/wanmeishenghuo/p/9650726.html 参考狄泰软件相关教程
问题:
如何遍历单链表中的每一个元素?
示例:
在头部插入元素时,时间复杂度是O(n)。 获取元素时,时间复杂度是O(n*n),因为内层定位位置时有一个O(n)复杂度。
从理论上来说遍历一个单链表,只需要线性的时间就够了。
设计思路:
提供一组相关的遍历函数,遍历时使用这些函数来操作:
move函数的i参数为目标位置,step参数为每次移动的节点数。
end用来判断当前的游标是否到达了单链表的尾部。
current返回当前游标指向的数据元素。
next移动游标,移动的次数根据move中的step的值来决定。
遍历时,这四个函数必须配合使用才能得到最大效率。
改进LinkList.h文件中的函数:
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template < typename T > class LinkList : public List<T> { protected: struct Node : public Object { T value; Node* next; }; mutable struct : public Object { char reserved[sizeof(T)]; Node* next; }m_header; int m_length; int m_step; Node* m_current; Node* position(int i) const // O(n) { Node* ret = reinterpret_cast<Node*>(&m_header); for(int p = 0; p < i; p++) { ret = ret->next; } return ret; } public: LinkList() { m_header.next = NULL; m_length = 0; m_step = 1; m_current = NULL; } bool insert(const T& e) { return insert(m_length, e); } bool insert(int i, const T& e) // O(n) { bool ret = ((0 <= i) && (i <= m_length)); if( ret ) { Node* node = new Node(); if( node != NULL ) { Node* current = position(i); node->value = e; node->next = current->next; current->next = node; m_length++; } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element..."); } } return ret; } bool remove(int i) // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { Node* current = position(i); Node* toDel = current->next; current->next = toDel->next; delete toDel; m_length--; } return ret; } bool set(int i, const T& e) // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { position(i)->next->value = e; } return ret; } T get(int i) const { T ret; if( get(i, ret) ) { return ret; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ..."); } return ret; } bool get(int i, T& e) const // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { e = position(i)->next->value; } return ret; } int find(const T& e) const // O(n) { int ret = -1; int i = 0; Node* node = m_header.next; while( node ) { if( node->value == e ) { ret = i; break; } else { node = node->next; i++; } } return ret; } int length() const // O(1) { return m_length; } void clear() // O(n) { while( m_header.next ) { Node* toDel = m_header.next; m_header.next = toDel->next; delete toDel; } m_length = 0; } bool move(int i, int step = 1) { bool ret = (0 <= i) && (i < m_length) && (step > 0); if( ret ) { m_current = position(i)->next; m_step = step; } return ret; } bool end() { return (m_current == NULL); } T current() { if( !end() ) { return m_current->value; } else { THROW_EXCEPTION(InvalidOperationException, "No value at current position ..."); } } bool next() //每次移动step步 { int i = 0; while((i < m_step) && !end()) { m_current = m_current->next; i++; } return (i == m_step); } ~LinkList() // O(n) { clear(); } }; } #endif // LINKLIST_H
第27、28行我们添加了两个成员变量,第185-226行添加了遍历需要的函数。
测试程序如下:
#include <iostream> #include "LinkList.h" using namespace std; using namespace DTLib; int main() { LinkList<int> list; for(int i = 0; i<5; i++) { list.insert(0,i); } //遍历时必须先调用move函数 for(list.move(0); !list.end(); list.next()) { cout << list.current() << endl; } return 0; }
遍历list时必须先调用move函数,指定位置和步进值step,step是给next函数用的,例如:step为5,则每次调用next函数就会向后移动5个元素。
结果如下:
这时的遍历操作时间复杂度是O(n)。
步进值为2时,结果如下:
单链表内部封装:
程序改进:
#ifndef LINKLIST_H #define LINKLIST_H #include "List.h" #include "Exception.h" namespace DTLib { template < typename T > class LinkList : public List<T> { protected: struct Node : public Object { T value; Node* next; }; mutable struct : public Object { char reserved[sizeof(T)]; Node* next; }m_header; int m_length; int m_step; Node* m_current; Node* position(int i) const // O(n) { Node* ret = reinterpret_cast<Node*>(&m_header); for(int p = 0; p < i; p++) { ret = ret->next; } return ret; } virtual Node* create() { return new Node(); } virtual void destroy(Node* pn) { delete pn; } public: LinkList() { m_header.next = NULL; m_length = 0; m_step = 1; m_current = NULL; } bool insert(const T& e) { return insert(m_length, e); } bool insert(int i, const T& e) // O(n) { bool ret = ((0 <= i) && (i <= m_length)); if( ret ) { Node* node = create(); if( node != NULL ) { Node* current = position(i); node->value = e; node->next = current->next; current->next = node; m_length++; } else { THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element..."); } } return ret; } bool remove(int i) // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { Node* current = position(i); Node* toDel = current->next; current->next = toDel->next; destroy(toDel); m_length--; } return ret; } bool set(int i, const T& e) // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { position(i)->next->value = e; } return ret; } T get(int i) const { T ret; if( get(i, ret) ) { return ret; } else { THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ..."); } return ret; } bool get(int i, T& e) const // O(n) { bool ret = ((0 <= i) && (i < m_length)); if( ret ) { e = position(i)->next->value; } return ret; } int find(const T& e) const // O(n) { int ret = -1; int i = 0; Node* node = m_header.next; while( node ) { if( node->value == e ) { ret = i; break; } else { node = node->next; i++; } } return ret; } int length() const // O(1) { return m_length; } void clear() // O(n) { while( m_header.next ) { Node* toDel = m_header.next; m_header.next = toDel->next; destroy(toDel); } m_length = 0; } bool move(int i, int step = 1) { bool ret = (0 <= i) && (i < m_length) && (step > 0); if( ret ) { m_current = position(i)->next; m_step = step; } return ret; } bool end() { return (m_current == NULL); } T current() { if( !end() ) { return m_current->value; } else { THROW_EXCEPTION(InvalidOperationException, "No value at current position ..."); } } bool next() //每次移动step步 { int i = 0; while((i < m_step) && !end()) { m_current = m_current->next; i++; } return (i == m_step); } ~LinkList() // O(n) { clear(); } }; } #endif // LINKLIST_H
调用new生成Node的地方我们全换成了create函数,调用delete销毁Node的地方我们全换成了destroy函数。
问题:
封装这两个函数的意义是什么?
小结: