效率分析
template <typename T>
class SqlList : public List<T>
{
public:
bool insert(const T &e); // O(1)
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: 对象析构时,同一堆空间被释放两次
- 分析:对于容器类型的类,可以考虑禁用拷贝构造和赋值操作.
template <typename T>
class List : public Object
{
protected:
List(const List&);
List &operator= (const List&);
public:
List() { }
// ...
};
课程中的解释:面向对象是将生活中的概念平行搬移到程序设计中,而生活中无法完成两个容器的拷贝动作。
文件:List.h
#ifndef LIST_H
#define LIST_H
#include "Object.h"
namespace DTLib
{
template<typename T>
class List : public Object
{
public:
List() {}
virtual bool insert(const T &e) = 0;
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, 下表合法性检查无法通过,抛出异常
问题分析
顺序存储结构线性表提供了数组操作符重载,通过重载能够快捷方便的获取目标位置处的数据元素,在具体的使用形式上类似数组,但由于本质不同,不能代替数组使用。
- 线性表必须先插入元素,才能使用操作符 [] 访问元素
实战预告:数组类开发
小结
- 顺序存储线性表的插入和删除操作存在重在效率隐患
- 线性表作为容器,应该避免拷贝构造和拷贝赋值
- 顺序存储线性表可能被当成数组误用
- 工程开发中可以考虑使用数组类代替原生数组使用
以上内容整理于狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。