《算法導論》10.2-5 使用單向循環鏈表實現字典操做插入、刪除、查找,並給出運行時間。ios
單鏈表雖然不能像雙鏈表同樣,實如今任意位置上時間O(1)的插入刪除,可是能夠在預先指定的位置上實現O(1)時間的插入刪除。由於只有該位置的前驅後繼兩個元素會受到影響,只要維護起這兩個元素的信息就夠了。算法
也由於這一點,當使用鏈表實現棧和隊列的時候,採用單鏈表和雙鏈表的運行時間是同樣的,單鏈表更節省空間。
~~~this
template
class SingleLinkedList
{
public:
SingleLinkedList()
{
init();
}
SingleLinkedList(const SingleLinkedList& rhs)
{
init();
for(Node* p = rhs.sentinel->next; p != rhs.sentinel; p = p->next)//Error Note: ++p
push_back(p->object);
}
SingleLinkedList(SingleLinkedList&& rhs)
{
sentinel = rhs.sentinel;
sentinelPrev = rhs.sentinelPrev;
rhs.sentinel = rhs.sentinelPrev = nullptr;
}
SingleLinkedList& operator =(const SingleLinkedList& rhs)
{
auto copy(rhs);
std::swap(copy.sentinel, this->sentinel);
std::swap(copy.sentinelPrev, this->sentinelPrev);
return
this;
}
SingleLinkedList& operator =(SingleLinkedList&& rhs)
{
std::swap(rhs.sentinel, this->sentinel);
std::swap(rhs.sentinelPrev, this->sentinelPrev);
return this;
}
~SingleLinkedList()
{
if(sentinel)
{
while(!empty())
pop_front();
delete sentinel;
sentinel = sentinelPrev = nullptr;
}
}
//push操做的運行時間都是O(1)
void push_back(const Object& object)
{
Node* pNew = new Node{object, sentinel};
sentinelPrev->next = pNew;
sentinelPrev = pNew;
}code
void push_back(Object&& object)
{
Node* pNew = new Node{std::move(object), sentinel};
sentinelPrev->next = pNew;
sentinelPrev = pNew;
}遞歸
void push_front(const Object& object)
{
Node* pNew = new Node{object, sentinel->next};
if(empty())
sentinelPrev = pNew;
sentinel->next = pNew;
}隊列
void push_front(Object&& object)
{
Node* pNew = new Node{std::move(object), sentinel->next};
if(empty())
sentinelPrev = pNew;
sentinel->next = pNew;
}string
void pop_front()
{
if(!empty())
erase(sentinel);
}it
void erase(const Object& object)
{
Node* prev = findPrev(object);
if(prev)
erase(prev);
}io
Object* find(const Object& object) //運行時間O(n)
{
Node* prev = findPrev(object);
if(prev)
return &(prev->next->object);
else
return nullptr;
}
const Object* find(const Object &object) const
{
const Node* prev = findPrev(object);
if(prev)
return &(prev->next->object);
else
return nullptr;
}
bool empty()const{ return sentinelPrev == sentinel;}
/《算法導論》10.2-7 給出一個O(n)時間的非遞歸過程,實現對一個含有n個元素的單鏈表的逆轉,要求除存儲鏈表自己所需的空間外,該過程只能使用固定大小的存儲空間/
void invert()
{
Node* prev = sentinel, current = sentinel->next, next = nullptr;
while(current != sentinel)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
current->next = prev;
}
private:
struct Node
{
Object object;
Node* next;
};
Node* sentinel;
Node* sentinelPrev;
void init() { sentinel = new Node; sentinel->next = sentinelPrev = sentinel; } //刪除p的後繼節點, 運行時間O(1) void erase(Node* p) { auto pDelete = p->next; p->next = pDelete->next; if(p->next == sentinel) sentinelPrev = p; delete pDelete; //Error Note: delete p->next; pDelete should be used } const Node* findPrev(const Object& object) const { for(const Node *prev = sentinel, *current = sentinel->next; current != sentinel; prev = current, current = current->next) { if(current->object == object) return prev; } return nullptr;//Error Note: forgotten } Node* findPrev(const Object& object) { for(Node *prev = sentinel, *current = sentinel->next; current != sentinel; prev = current, current = current->next) { if(current->object == object) return prev; } return nullptr; }
};
void testSingleLinkedList()
{
using namespace std;
struct Student
{
const char* name;
int age;
bool operator ==(const Student& rhs) const
{
return 0 == strcmp(name, rhs.name) && age == rhs.age;
}
};
constexpr int NUM = 5;
Student students[NUM] = {Student{"Tom", 12},Student{"Micheal", 13},
Student{"Anna", 14},Student{"Lily", 10},
Student{"James", 19}};
SingleLinkedList
sl.push_back(students[0]);
sl.push_back(students[1]);
sl.push_back(Student{"Anna", 14});
sl.push_front(students[3]);
sl.push_front(students[4]);
Student* tom = sl.find(students[0]);
tom->age = 20;
tom = sl.find(students[0]);
if(tom == nullptr)
cout << "cannot find {Tom, 12}" << endl;
students[0].age = 20;
sl.pop_front();
sl.erase(students[3]);
sl.erase(students[1]);
sl.erase(students[2]);
tom = sl.find(students[0]);
cout << tom->age << endl;
const decltype(sl) sl_copy(sl);
const Student* tom1 = sl_copy.find(students[0]);
cout << tom1->age << endl;
decltype(sl) sl_move(sl);
tom = sl_move.find(students[0]);
cout << tom->age << endl;
sl_move = sl_copy;
tom = sl_move.find(students[0]);
cout << tom->age << endl;
}
/test output: cannot find {Tom, 12} 20 20 20 20/ ~~~