程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 數據結構基礎(12) --雙向循環鏈表的設計與實現

數據結構基礎(12) --雙向循環鏈表的設計與實現

編輯:C++入門知識

數據結構基礎(12) --雙向循環鏈表的設計與實現


雙向鏈表的操作特點:

(1) “查詢” 和單鏈表相同;

(2)“插入” 和“刪除”時需要同時修改兩個方向上的指針。

但是對於雙向循環鏈表則在表尾插入非常的迅速, 只需O(1)的時間,因為有指向前面的指針, 因此雙向循環鏈表會很容易的找到位於表尾的元素,因此雙向循環鏈表比較適用於頻繁在表尾插入的情況.

\


空鏈表:

\

雙向循環鏈表節點構造:

class DoubleListNode
{
private:
    Type data;
    DoubleListNode *prev;   //前向指針域
    DoubleListNode *next;   //後項指針域
};

因為需要將其用於DoubleList類,因此需要將其改造如下:

template 
class DoubleListNode
{
    //友元聲明
    friend class DoubleList;
    friend class ListIterator;

    template 
    friend ostream &operator<<(ostream &os, const DoubleList &list);
private:
    DoubleListNode(const Type &dataValue)
        :data(dataValue),prev(NULL),next(NULL) {}

    Type data;
    DoubleListNode *prev;   //前向指針域
    DoubleListNode *next;   //後項指針域
};

雙向循環鏈表構造:

template 
class DoubleList
{
    friend class ListIterator;
    template 
    friend ostream &operator<<(ostream &os, const DoubleList &list);
public:
    DoubleList();
    ~DoubleList();

    void push_back(const Type &data);
    void push_front(const Type &data);
    void insert(int position, const Type &data);

    void pop_front();
    void pop_back();
    void remove(const Type &removeData);

    bool search(const Type &searchData) const;
    bool isEmpty() const
    {
        return (first->next == first);
    }

private:
    //將節點x插入到節點previous後面
    void insertPrivate(DoubleListNode *previous,
                       DoubleListNode *x);
    void removePrivate(DoubleListNode *x);

private:
    DoubleListNode *first;
};

鏈表的構造與析構:

//構造鏈表
template 
DoubleList::DoubleList()
{
    first = new DoubleListNode(0);
    first->next = first;
    first->prev = first;
}
//析構鏈表
template 
DoubleList::~DoubleList()
{
    DoubleListNode *deleteNode = NULL;
    //保存鏈表尾元素
    DoubleListNode *tmp = first;

    //first首先指向第一個真實的元素
    first = first->next;
    //一路到達鏈表結尾
    while (first != tmp)
    {
        deleteNode = first;
        first = first -> next;
        delete deleteNode;
    }
    // 釋放掉鏈表的空節點(表頭)
    delete tmp;
}

鏈表元素插入與刪除的兩大主力:

//同為private成員
//插入節點
template 
void DoubleList::insertPrivate(DoubleListNode *previous,
                                     DoubleListNode *x)
{
    x->prev = previous;
    x->next = previous->next;
    previous->next->prev = x;
    previous->next = x;
}

//刪除節點
template 
void DoubleList::removePrivate(DoubleListNode *x)

{
    if (x == first)
        throw std::range_error("permission denied to delete first pointer");

    x->prev->next = x->next;
    x->next->prev = x->prev;
    delete x;
}

提供給客戶的插入:

//插入到表尾
template 
void DoubleList::push_back(const Type &data)
{
    DoubleListNode *newNode = new DoubleListNode(data);
    //找到first的前一個節點
    DoubleListNode *previous = first->prev;

    //插入
    insertPrivate(previous, newNode);
}
//插入到表頭
template 
void DoubleList::push_front(const Type &data)
{
    DoubleListNode *newNode = new DoubleListNode(data);
    //插入到first之後
    insertPrivate(first, newNode);
}

//插入到任意位置(依position指定)
template 
void DoubleList::insert(int position, const Type &data)
{
    if (position == 1)
        return push_front(data);

    int count = 1;
    //previous 代表著要插入位置之前的一個位置
    DoubleListNode *previous = first->next;

    //如果position過大, 則previous查找到first就會停止
    //此時應該將該元素插入到鏈表結尾
    while (count < position-1 && previous != first)
    {
        ++ count;
        previous = previous->next;
    }

    //如果查找到了鏈表結尾或此時鏈表為空, 因此插入到表尾
    if (previous == first)
        return push_back(data);

    //如果找到了合適的插入位置
    DoubleListNode *newNode = new DoubleListNode(data);
    insertPrivate(previous, newNode);
}

提供給客戶的刪除:

//刪除表尾元素
template 
void DoubleList::pop_back()
{
    removePrivate(first->prev);
}
//刪除表頭元素
template 
void DoubleList::pop_front()
{
    removePrivate(first->next);
}

//刪除元素值為removeData的所有元素
template 
void DoubleList::remove(const Type &removeData)
{
    if (isEmpty())
        throw std::range_error("link list is empty");

    for( DoubleListNode *searchNode = first->next;
            searchNode != first;
            searchNode = searchNode->next)
    {
        if (searchNode->data == removeData)
            removePrivate(searchNode);
    }
}

查看是否存在於鏈表中:

template 
bool DoubleList::search(const Type &searchData) const
{
    DoubleListNode *searchNode = first->next;
    while (searchNode != first)
    {
        if (searchNode->data == searchData)
            return true;

        searchNode = searchNode->next;
    }
    return false;
}

輸出鏈表所有元素(測試用):

template 
ostream &operator<<(ostream &os, const DoubleList &list)
{
    for (DoubleListNode *currentNode = (list.first)->next;
            currentNode != list.first;
            currentNode = currentNode->next)
        os << currentNode->data << ' ';

    return os;
}

雙向循環鏈表迭代器的設計與實現:

//除了添加了operator--, 幾乎沒做任何改變
template 
class ListIterator
{
public:
    ListIterator(const DoubleList &_list):
        list(_list),
        currentNode((_list.first)->next) {}

    //重載 *operator
    const Type &operator*() const throw (std::out_of_range);
    Type &operator*() throw (std::out_of_range);

    //重載 ->operator
    const DoubleListNode *operator->() const throw (std::out_of_range);
    DoubleListNode *operator->() throw (std::out_of_range);

    //重載 ++operator
    ListIterator &operator++() throw (std::out_of_range);
    //注意:此處返回的是值,而不是reference
    ListIterator operator++(int) throw (std::out_of_range);

    //重載 --operator,
    // 其實這個版本的--operator是不完美的,
    // 因為他沒有做任何的判錯控制
    ListIterator &operator--();
    //注意:此處返回的是值,而不是reference
    ListIterator operator--(int);

    bool isEmpty() const
    {
        return (currentNode == list.first);
    }

private:
    const DoubleList &list;
    DoubleListNode *currentNode;
};
template 
const Type &ListIterator::operator*() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    // 返回當前指針指向的內容
    return currentNode->data;
}
template 
Type &ListIterator::operator*()
throw (std::out_of_range)
{
    return
        const_cast(
            static_cast &>(*this).operator*()
        );
}
template 
const DoubleListNode *ListIterator::operator->() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");

    //直接返回指針
    return currentNode;
}

template 
DoubleListNode *ListIterator::operator->()
throw (std::out_of_range)
{
    return
        const_cast *> (
            static_cast >(*this).operator->()
        );
}
template 
ListIterator &ListIterator::operator++()
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //指針前移
    currentNode = currentNode->next;
    return *this;
}
template 
ListIterator ListIterator::operator++(int)
throw (std::out_of_range)
{
    ListIterator tmp(*this);
    ++ (*this); //調用前向++版本

    return tmp;
}
template 
ListIterator &ListIterator::operator--()
{
    //指針前移
    currentNode = currentNode->prev;
    return *this;
}
template 
ListIterator ListIterator::operator--(int)
{
    ListIterator tmp(*this);
    -- (*this);

    return tmp;
}

測試代碼:

int main()
{
    cout << "-------- 1 --------" << endl;
    DoubleList myList;

    for (int i = 0; i < 3; ++i)
        myList.push_back(i+1);
    for (int i = 0; i < 5; ++i)
        myList.push_front(10+i);
    for (int i = 0; i < 3; ++i)
        myList.push_back(i+1);

    ListIterator iter(myList), iter2(myList);
    while (!iter.isEmpty())
    {
        cout << *iter << ' ';
        ++ iter;

        ++ iter2;
    }
    cout << endl;

    -- iter2;
    while (!iter2.isEmpty())
    {
        cout << *iter2 << ' ';
        iter2 --;
    }
    cout << endl;

    cout << "-------- 2 --------" << endl;

    cout << myList << endl;
    cout << "Test insert..." << endl;
    myList.insert(1, 14);
    myList.insert(2, 13);
    myList.insert(2, 13);
    myList.insert(88, 88);
    cout << myList << endl;

    myList.pop_back();
    myList.pop_front();
    cout << myList << endl;

    for (int i = 0; i < 5; ++i)
    {
        if (myList.search(i))
            cout << i << ": Have found!" << endl;
        else
            cout << i << ": Not in the list!" << endl;
    }

    cout << "Test remove..." << endl;
    cout << myList << endl;
    int value;
    while (cin >> value)
    {
        try
        {
            myList.remove(value);
        }
        catch (const std::exception &e)
        {
            cerr << e.what() << endl;
        }

        cout << myList << endl;
        if (myList.isEmpty())
        {
            cout << "empty" << endl;
        }
        else
        {
            cout << "not empty" << endl;
        }
    }

    return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved