程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 數據結構基礎(10)

數據結構基礎(10)

編輯:關於C++

為了向 STL 致敬(O(∩_∩)O~), 我們模仿STL中的list的迭代器, 我們也自己實現一個MyList的迭代器, 以供遍歷整個鏈表的所有元素:

首先:Node節點需要做如下修改(注意後綴有+的代碼)

//鏈表節點
template 
class Node
{
    friend class MyList;
    friend class ListIterator;	//+

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

    Type data;  //數據域:節點數據
    Node *next; //指針域:下一個節點
};

然後:MyList類同樣也需要做修改,但是由於MyList類過長, 修改之處也較少, 因此在此就不貼出, 完整代碼會附到博客最後

ListIterator的設計

template 
class ListIterator
{
public:
    ListIterator(const MyList &_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 Node *operator->() const throw (std::out_of_range);
    Node *operator->() throw (std::out_of_range);

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

    bool isEmpty() const;

private:
    const MyList &list;
    Node *currentNode;
};

ListIterator類的實現

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)
{
    //首先為*this添加const屬性,
    //以調用該函數的const版本,
    //然後再使用const_case,
    //將該函數調用所帶有的const屬性轉除
    //operator->()的non-const版本與此類同
    return
        const_cast(
            static_cast &>(*this).operator*()
        );
}

template 
const Node *ListIterator::operator->() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //直接返回指針
    return currentNode;
}

template 
Node *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 
bool ListIterator::isEmpty() const
{
    if (currentNode == NULL)
        return true;
    return false;
}

附-ListIterator測試代碼:

int main()
{
    std::list iStdList;
    MyList    iMyList;
    for (int i = 0; i < 10; ++i)
    {
        iStdList.push_back(i+1);
        iMyList.insert(i+1, i+1);
    }

    for (std::list::iterator iter = iStdList.begin();
            iter != iStdList.end();
            ++ iter)
    {
        cout << *iter << ' ';
    }
    cout << endl;

    for (ListIterator iter(iMyList);
            !iter.isEmpty();
            ++ iter)
    {
        cout << *iter << ' ';
    }
    cout << endl;

    cout << "Test: \n\t" << iMyList << endl;


    ListIterator iter(iMyList);
cout << "first = " << *iter << endl;
}


附-MyList完整源代碼

//MyList.h
#ifndef MYLIST_H_INCLUDED
#define MYLIST_H_INCLUDED

#include 
#include 
using namespace std;

//前向聲明
template 
class MyList;
template 
class ListIterator;

//鏈表節點
template 
class Node
{
    //可以將MyList類作為Node的友元
    //同時也可以將Node類做成MyList的嵌套類, 嵌套在MyList中, 也可以完成該功能
    friend class MyList;
    friend class ListIterator;

    template 
    friend ostream &operator<<(ostream &os, const MyList &list);
private:
    //constructor說明:
    //next = NULL;    //因為這是一個新生成的節點, 因此下一個節點為空
    Node(const Type &dataValue):data(dataValue), next(NULL) {}

    Type data;  //數據域:節點數據
    Node *next; //指針域:下一個節點
};

//鏈表
template 
class MyList
{
    template 
    friend ostream &operator<<(ostream &os, const MyList &list);

    friend class ListIterator;
public:
    MyList();
    ~MyList();

    //將元素插入表頭
    void insertFront(const Type &data);
    //將元素插入到位置index上(index從1開始)
    void insert(const Type &data, int index);
    //刪除表中所有值為data的節點
    void remove(const Type &data);
    bool isEmpty() const;

    //鏈表反轉
    void invort();
    //將鏈表(list)鏈接到本條鏈表的末尾
    void concatenate(const MyList &list);

private:
    //指向第一個節點的指針
    Node *first;
};

template 
MyList::MyList()
{
    //first指向一個空節點
    first = new Node(0);
    first -> next = NULL;
}
template 
MyList::~MyList()
{
    Node *deleteNode = NULL;
    while (first != NULL)
    {
        deleteNode = first;
        first = first -> next;
        delete deleteNode;
    }
}

template 
void MyList::insertFront(const Type &data)
{
    Node *newNode = new Node(data);
    newNode -> next = first -> next;
    first -> next = newNode;
}

template 
void MyList::insert(const Type &data, int index)
{
    //由於我們在表頭添加了一個空節點
    //因此如果鏈表為空, 或者在鏈表為1的位置添加元素
    //其操作與在其他位置添加元素相同

    int count = 1;
    //此時searchNode肯定不為NULL
    Node *searchNode = first;
    // 找到要插入的位置
    // 如果所給index過大(超過了鏈表的長度)
    // 則將該元素插入到鏈表表尾
    // 原因是 searchNode->next != NULL 這個條件已經不滿足了
    // 已經到達表尾
    while (count < index && searchNode->next != NULL)
    {
        ++ count;
        searchNode = searchNode->next;
    }

    // 插入鏈表
    Node *newNode = new Node(data);
    newNode->next = searchNode->next;
    searchNode->next = newNode;
}

template 
void MyList::remove(const Type &data)
{
    if (isEmpty())
        return ;

    Node *previous = first;   //保存要刪除節點的前一個節點
    for (Node *searchNode = first->next;
            searchNode != NULL;
            searchNode = searchNode->next)
    {
        if (searchNode->data == data)
        {
            previous->next = searchNode->next;
            delete searchNode;
            //重新調整searchNode指針
            //繼續遍歷鏈表查看是否還有相等元素

            //如果當前searchNode已經到達了最後一個節點
            //也就是searchNode->next已經等於NULL了, 則下面這條語句不能執行
            if (previous->next == NULL)
                break;

            searchNode = previous->next;
        }
        previous = searchNode;
    }
}
template 
bool MyList::isEmpty() const
{
    return first->next == NULL;
}

template 
void MyList::concatenate(const MyList &list)
{
    if (isEmpty())//如果自己的鏈表為空
    {
        first = list.first;
        return ;
    }
    else if (list.isEmpty())    //如果第二條鏈表為空
    {
        return ;
    }

    Node *endNode = first->next;
    //找到第一條鏈表的末尾節點
    while (endNode->next != NULL)
    {
        endNode = endNode->next;
    }

    //找到第二條鏈表的第一個真實元素
    Node *secondListNode = (list.first)->next;
    //注意: 需要將第二個鏈表中的元素值copy出來
    //不能直接將第二條鏈表的表頭鏈接到第一條鏈表的表尾
    //不然在析構函數回收內存時會發生錯誤(即:同一段內存釋放兩次)
    while (secondListNode != NULL)
    {
        Node *newNode = new Node(secondListNode->data);
        newNode->next = NULL;
        endNode->next = newNode;

        //兩條鏈表同時前進
        endNode = endNode->next;
        secondListNode = secondListNode->next;
    }
}

template 
void MyList::invort()
{
    if (!isEmpty())
    {
        //p指向正向鏈表的第一個真實節點
        //隨後, p也會沿正方向遍歷到鏈表末尾
        Node *p = first->next;

        //q會成為倒向的第一個真實節點
        //首先將q設置為NULL: 保證反向之後
        //最後一個元素的指針域指向NULL, 以表示鏈表結束
        Node *q = NULL;
        while (p != NULL)
        {
            Node *r = q;  //暫存q當前指向的節點
            //q後退(沿著正向後退)
            q = p;
            //p前進(沿著正向前進), 保證p能夠始終領先q一個位置
            p = p -> next;
            //將指針逆向反轉
            //注意:一點要保證這條語句在p指針移動之後運行,
            //不然p就走不了了...(因為q改變了指針的朝向)
            q -> next = r;
        }

        //此時q成為反向鏈表的第一個真實元素
        //但是為了維護像以前一樣的first指針指向一個無用的節點(以使前面的操作不會出錯)
        //於是我們需要將first的指針域指向q
        first->next = q;
    }
}

//顯示鏈表中的所有數據(測試用)
template 
ostream &operator<<(ostream &os, const MyList &list)
{
    for (Node *searchNode = list.first -> next;
            searchNode != NULL;
            searchNode = searchNode -> next)
    {
        os << searchNode -> data;
        if (searchNode -> next != NULL) //尚未達到鏈表的結尾
            cout << " -> ";
    }

    return os;
}

//ListIterator的設計與實現
template 
class ListIterator
{
public:
    ListIterator(const MyList &_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 Node *operator->() const throw (std::out_of_range);
    Node *operator->() throw (std::out_of_range);

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

    bool isEmpty() const;

private:
    const MyList &list;
    Node *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)
{
    //首先為*this添加const屬性,
    //以調用該函數的const版本,
    //然後再使用const_case,
    //將該函數調用所帶有的const屬性轉除
    //operator->()的non-const版本與此類同
    return
        const_cast(
            static_cast &>(*this).operator*()
        );
}

template 
const Node *ListIterator::operator->() const
throw (std::out_of_range)
{
    if (isEmpty())
        throw std::out_of_range("iterator is out of range");
    //直接返回指針
    return currentNode;
}

template 
Node *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 
bool ListIterator::isEmpty() const
{
    if (currentNode == NULL)
        return true;
    return false;
}

#endif // MYLIST_H_INCLUDED

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