十、單鏈表的遍歷與優化


1、單鏈表遍歷優化

遍歷單鏈表中的每個一數據元素

LinkList<int> list;
for(int i = 0; i < 5; i++)	// O(n)
{
    list.insert(0, i);	// O(1), 頭部插入,不涉及循環
}
// 這里的遍歷方法效率很低
for(int i = 0; i < list.length(); i++)  // O(n^2)
{
    cout << list.get(i) << endl;    // O(n)
}

遍歷鏈表的時間復雜度不是線性的,插入元素是線性,遍歷就不是了。

不能以線性的時間復雜度完成單鏈表的遍歷

新的需求:為單鏈表提供新的方法,在線性時間內完成遍歷

設計思路(游標)

  • 在單鏈表的內部定義一個游標Node* m_current
  • 遍歷開始前將游標指向位置為0的數據元素
  • 獲取游標指向的數據元素
  • 通過結點中的next指針移動游標

提供一組遍歷相關的函數,以線性的時間復雜度遍歷鏈表

遍歷函數原型設計

bool move(int i, int step = 1);
bool end();
T current();
bool next();	// 移動次數根據step的值來確定
// i 目標位置,step 游標每次移動結點的數目
    bool move(int i, int step = 1)
    {
        bool ret = ((i >= 0) && (i < m_length) && (step > 0));
        if(ret)
        {
            // 將游標定位到目標位置i的地方
            m_current = position(i)->next;
            m_step = step;
        }
        return ret;
    }

    bool end()
    {
        return (m_current == NULL);
    }

    T current()
    {
        // 返回游標指向的位置的元素值
        //if(m_current != NULL)
        if(!end())
        {
            return m_current->value;
        }
        else
        {
            THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
        }
    }

    bool next()
    {
        int i = 0;
        while((i<m_step) && !end())
        {
            m_current = m_current->next;
            i++;
        }
        // i的值和m_step的值是一樣的,就表示移動成功
        return (i == m_step);
    }


// 新的遍歷使用方法
for(list.move(0); !list.end(); list.next()) // O(n)
{
    cout << list.current() << endl;
}

2、單鏈表內部的一次封裝

virtual Node* creat()
{
    return new Node();
}
virtual void destory(Node* pn)
{
    delete pn;
}

3、小結

單鏈表的遍歷需要在線性時間內完成

在單鏈表內部定義游標變量,通過游標變量提高效率

遍歷相關的成員函數是相互依賴,相互配合的關系

封裝結點的申請和刪除操作更有利於增強擴展性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM