1. 程式人生 > >6. 帶哨兵的單向迴圈連結串列

6. 帶哨兵的單向迴圈連結串列

  • 《演算法導論》10.2-5 使用單向迴圈連結串列實現字典操作 INSERT、DELETE、SEARCH,並給出執行時間。
#include <iostream>
#include <string.h>
template<typename Object>
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;
    }

    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;
    }

    void pop_front()
    {
        if(!empty())
            erase(sentinel);
    }

    void erase(const Object& object)
    {
        Node* prev = findPrev(object);
        if(prev)
            erase(prev);
    }

    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;}

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<Student> sl;
    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*/