1. SeqList类的效率分析
长度相同的两个SeqList,插入和删除操作的平均耗时不一定相同。
如SeqList<int> s1和SeqList<string> s2的插入操作,由于string的赋值涉及到字符串的拷贝,这就比int类型的拷贝耗时,因此s1和s2的平均耗时是不同的。
2、问题一:对象赋值的问题
1 StaticList<int* ,5> s1; 2 StaticList<int* ,5> s2; 3 for(int i=0 ;i<s1.capacity();i++) 4 { 5 s1.insert(0, new int(i));//s1线性表中第0个位置插入堆空间中的一个地址,地址中存的是i 6 } //s1中有5个指针每个指针指向一个堆空间中的一个的整形数据 7 8 s2=s1;//赋值可以成功 但是两个对象中的m_space[i]都指向同一个int*类型的堆空间 9 10 for(int i=0 ;i<s1.capacity();i++) 11 { 12 delete s1[i];//即释放所指向所指向的堆空间 13 delete s2[i]; 14 }
delete s1;
delete s2;
同一个堆空间被释放了两次,第二次释放了未定义的堆空间,一定发生问题,置于何时会变成bug就不知道了
问题二:对象拷贝问题
解决方案:对于容器类型的类,可以考虑禁用拷贝构造和赋值操作。将拷贝构造函数和赋值的的操作符声明为protected(可以被子类访问不能被外界访问的)
List.h和SeqList.h的改进
//List.h
1 #ifndef _LIST_H_ 2 #define _LIST_H_ 3 4 #include "Object.h" 5 6 namespace DTLib { 7 8 template <typename T> 9 class List : public Object 10 { 11 protected: 12 //禁用拷贝构造函数和赋值操作符 即将拷贝构造函数和赋值操作法声明为保护的; 13 List(const List&); 14 List& operator=(const List&); 15 public: 16 //由于以上手动添加了拷贝构造函数,编译将不再提供 17 //默认的一些构造函数。这里需要手工加上无参构造函数 18 List(){} 19 virtual bool insert(const T& e) = 0;//往线性表尾部插入元素 20 virtual bool insert(int index, const T& elem) = 0; 21 virtual bool remove(int index) = 0; 22 virtual bool get(int index, T& elem) const = 0; 23 virtual int length() const = 0; 24 virtual void clear() = 0; 25 }; 26 27 } 28 29 #endif // _LIST_H_
//SeqList.h
1 #ifndef _SEQLIST_H_ 2 #define _SEQLIST_H_ 3 4 #include "list.h" 5 #include "Exception.h" 6 7 namespace DTLib { 8 9 template <typename T> 10 class SeqList : public List<T> 11 { 12 protected: 13 T* m_array; //顺序存储空间 14 int m_length; //当前线性表长度 15 public: 16 //插入元素 17 bool insert(int index, const T &elem) //O(n) 18 { 19 bool ret = ((0 <= index)&&(index <= m_length)); 20 ret = ret && (m_length < capacity()); 21 22 if(ret){ 23 //将index及其之后的元素向后移动一个位置 24 for(int pos=m_length-1; pos>=index; pos--){ 25 m_array[pos + 1] = m_array[pos]; 26 } 27 //新元素插入在index位置 28 m_array[index] = elem; 29 m_length++; 30 } 31 32 return ret; 33 } 34 35 bool insert(const T& e) //O(n) ==>往线性表尾部插入元素 36 { 37 return insert(m_length, e); 38 } 39 40 //删除元素 41 bool remove(int index) //O(n) 42 { 43 bool ret = ((0 <= index)&&(index < m_length)); 44 45 if(ret){ 46 for(int pos=index; pos<m_length-1; pos++){ 47 m_array[pos] = m_array[pos + 1]; 48 } 49 50 m_length--; 51 } 52 53 return ret; 54 } 55 56 //设置元素 57 bool set(int index, const T& elem) //O(1) 58 { 59 bool ret = ((0 <= index)&&(index < m_length)); 60 61 if(ret){ 62 m_array[index] = elem; 63 } 64 65 return ret; 66 } 67 68 //获取元素 69 bool get(int index, T &elem) const //O(1) 70 { 71 bool ret = ((0 <= index)&&(index < m_length)); 72 73 if(ret){ 74 elem = m_array[index]; 75 } 76 77 return ret; 78 } 79 80 //当前长度 81 int length()const //O(1) 82 { 83 return m_length; 84 } 85 86 //清空线性表 87 void clear() //O(1) 88 { 89 m_length = 0; 90 } 91 92 //顺序存储线性表的数组访问方式 93 T& operator[](int index) //O(1) 94 { 95 if((0<=index) && (index<m_length)){ 96 return m_array[index]; 97 }else{ 98 THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter index is invalid ..."); 99 } 100 } 101 102 T operator [](int index) const //O(1) 103 { 104 return (const_cast<SeqList<T>&>(*this))[index]; 105 } 106 107 //顺序存储空间的容量 108 virtual int capacity()const = 0; 109 }; 110 111 } 112 113 #endif // _SEQLIST_H_