【數據結構】18_順尋存儲線性表的分析

效率分析

template <typename T>
class SqlList : public List<T>
{
public:
    bool insert(int i, const T &e);     // O(n)
    bool remove(int i);                 // O(n)
    bool set(int i, const T &e);        // O(1)
    bool get(int i, T &e) const;        // O(1)
    int length() const;                 // O(1)
    void clear();                       // O(1)
    
    T &operator[] (int i);              // O(1)
    T operator[] (int i) const;         // O(1)
    
    virtual int capacity() const = 0;   
};

問題

長度相同的兩個 SqlList, 插入和刪除操做的平均耗時是否相同?

不必定,須要具體狀況具體分析。
例:算法

SqlList<string> ss;
SqlList<string> si;

ss.insert(0, "D.T.Software");
si.insert(0, 1);

SqlList中,最耗時的是插入和刪除操做,由於要進行移位,尤爲當數據元素是自定義類類型,而且類很是龐大時耗時尤其明顯。
所以,分析一段代碼的效率,不可以只看時間複雜度(大O表示法),大O表示法僅爲參考指標,而非絕對指標。還須要具體狀況具體分析,當前算法是否真的知足需求。
由此也證實順序存儲表不適合類類型的元素存儲,適合基本類型。數組

下面的代碼正確嗎?爲何?

StaticList<int*, 5> s1;
StaticList<int*, 5> s2;

for (int i=0; i<s1.capacity(); ++i)
{
    s1.insert(0, new int(i));
}

s2 = s1;            // 注意 1

for (int i=0; i<s1.length(); ++i)
{
    delete s1[i];  // 注意 2
    delete s2[i];
}

不正確。
注意 1:兩鏈表中對應兩元素指向同一堆空間
注意 2:內存被釋放兩次,行爲未定義函數

下面的代碼正確嗎?爲何?

void func()
{
    DynamicList<int> d1(5);
    DynamicList<int> d2 = d1;   // 注意 1
    
    for (int i=0; i<d1.capacity(); ++i)
    {
        d1.insert(i, i);        // 注意 2
        d2.insert(i, i*i);      // 注意 2
    }
    
    for (int i=0; i<d1.lenth(); ++i)
    {
        cout >> d1[i] << endl;
    }
}

不正確。
注意 1: 兩鏈表中對應兩元素指向同一堆空間
注意 2: d1中插入的數據被重寫
注意 3: 對象析構時,同一堆空間被釋放兩次spa

  • 分析:對於容器類型的類,能夠考慮禁用拷貝構造和賦值操做.
template <typename T>
class List : public Object
{
protected:
    List(const List&);
    List &operator= (const List&);
public:
    List() { }
    // ...
};

課程中的解釋:面向對象是將生活中的概念平行搬移到程序設計中,而生活中沒法完成兩個容器的拷貝動做。設計

文件:List.hcode

#ifndef LIST_H
#define LIST_H

#include "Object.h"

namespace DTLib
{

template<typename T>
class List : public Object
{
public:
    List() {}
    virtual bool insert(int i, const T &e) = 0;
    virtual bool remove(int i) = 0;
    virtual bool set(int i, const T &e) = 0;
    virtual bool get(int i, T &e) const = 0;
    virtual int length() const = 0;
    virtual void clear() = 0;

protected:
    List(const List&);
    List<T> &operator= (const List&);
};

}

#endif // LIST_H

下面的代碼正確嗎?爲何?

int main()
{
    StaticList<int, 5> list;
    
    for (int i=0; i<list.capacity(); ++i)
    {
        list[i] = i * i;
    }
    
    return 0;
}

不正確。
在 [] 數組操做符重載函數中可見, m_length 爲 0, 下表合法性檢查沒法經過,拋出異常對象

問題分析

順序存儲結構線性表提供了數組操做符重載,經過重載可以快捷方便的獲取目標位置處的數據元素,在具體的使用形式上相似數組,但因爲本質不一樣,不能代替數組使用。blog

  • 線性表必須先插入元素,才能使用操做符 [] 訪問元素

實戰預告:數組類開發

image.png

小結

  • 順序存儲線性表的插入和刪除操做存在重在效率隱患
  • 線性表做爲容器,應該避免拷貝構造和拷貝賦值
  • 順序存儲線性表可能被當成數組誤用
  • 工程開發中能夠考慮使用數組類代替原生數組使用

以上內容整理於狄泰軟件學院系列課程,請你們保護原創!內存

相關文章
相關標籤/搜索