昨天向量那章沒看完,今天繼續看
常規向量
書中實現了一個向量類的基本接口的方法,在此記錄一下
置亂方法
template<typname T> void permute(Vector<T>& v)
{
for(int i = v.size; i > 0; i--)
{
swap(v[i-1], v[rand() % i]);
//置換第i-1個元素與下標範圍在[0, i)間的任意一個元素
}
}
置亂某個區間的向量
template<typename T> void Vector<T>::permute(Rank lo, Rank hi)
{
T* v = _elem + lo;
//將子向量_elem[lo, hi]視爲新向量v[0, hi - lo]
for(Rank i = hi - lo; i > 0; i--)
{
swap(v[i], v[rand() % i]);
}
}
時間複雜度爲O(n)。
無序向量:支持比對(判等),未必支持比較(大小)的向量。
順序查找:逐個比對查找的方式。最好情況爲O(1),最壞情況爲O(n)。
template<typename T> Rank Vector<T>::find(const* e, Rank lo, Rank hi)
{
while((lo < hi --) && (e != _elem[hi])){ }
return hi;
}
插入:在位置r插入元素e:將n到r元素依次後移,將元素e賦值到位置r上。
template<typname T> void Vector<T>::insert(Rank r, const& e)
{
expand(); //如果有必要需要擴展數組
for(int i = size; i > 0; i--)
{
_elem[i] = _elem[i - 1];
}
_elem[r] = e;
size++;
}
刪除:刪除從lo到hi的元素:依次將從hi到n的元素賦值給從lo開始的地址。
template<typename T> void Vector<T>::remove(Rank lo, Rank hi)
{
if(hi > size) reuturn;
whil(hi < size)
{
_elem[lo++] = _elem[hi++];
}
size = size - hi + lo;
shrink(); //如果有必要需要縮小數組空間
}
去重:每次在範圍[0, i)內查找是否包含元素v[i],如果不包含則 i++,如果包含則刪除v[i]。由於同時包含了查找和刪除,二者的時間複雜度分別爲O(n),所以去重的總時間複雜度爲O(n(2))。
有序向量
所有元素按照線性次序存放,並且這些元素的數值也按照此次序單調分佈,稱爲有序向量。
由於不要求元素互異,通常約定非降序序列爲
對於任意 0<= i < j < n 都有 V[i] <= V[j]。
由於有序向量的特性,針對於有序向量的去重,如果還是用和無序向量中相同的去重方法則效率太低,所以有序向量中的去重利用有序向量的特性,設置兩個動態下標同時進行比較和替換,當兩個值不同時,將後一個值移到前一個值之後,最後直接截掉遍歷結束後尾部多餘的元素。
template<typename T> void Vector<T>::uniquify()
{
Rank i = 0;
Rank j = 0;
while(++j < size)
{
if(_elem[i] != _elem[j])
{
_elem[i++] = _elem[j];
}
}
size = i++;
shrink();
}
列表
元素也構成線性邏輯次序,但是元素的物理地址可以任意。“循位置訪問”/“循鏈接訪問”。
鏈表:典型動態存儲結構。其中的數據分散爲一系列節點,節點和節點之間通過指針相互索引和訪問。
默認構造方法,需運行常數時間
template<typename T> void List<T>::init()
{
header = new ListNode<T>;
trailer = new ListNode<T>;
header -> succ = trailer;
header -> pred = null;
trailer -> succ = null;
trailer -> pred = header;
size = 0;
}
查找,時間複雜度爲O(n)
template<typename T> ListNodePosi<T> List<T>::find(T const& e, int n, ListNodePosi<T> p)
{
while(n-- > 0)
{
if(e == (p = p -> pred) -> data)
{
return p;
}
}
return null;
}
前插入(在當前節點this前插入)
template<typename T> ListNodePosi<T> List<T>::InsertAsPred(T const& e)
{
ListNodePosi(T) x = new List(e, pred, this);
pred -> succ = x; //前結點的後繼爲x
pred = x; //當前結點的前驅爲x
return x;
}
後插入
template<typename T> ListNodePosi<T> List<T>::InsertAsSucc(T const& e)
{
ListNodePosi(T) x = new List(e, this, succ);
succ -> pred = x;
succ = x;
return x;
}
二者的時間複雜度均爲常數