您好,登錄后才能下訂單哦!
數組
數組是一種線性表數據結構。它用一組連續內存空間,來存儲一組具有相同數據類型數據。
1.線性表:數據存儲像一條線一樣的結構,每個線性表上的數據最多只有前和后的兩個方向,如數組、鏈表、隊列、棧等都是這種結構,所以實現的數組的動態操作,其他結構也可輕易的類似實現。更重要的是,在這之后看源碼就可大大降低難度。(博主自己看的是STL源碼剖析)
2.非線性表:如二叉樹、堆、圖等。
3連續內存空間和相同數據類型:當數組作插入、刪除操作時,為了保證數據的連續性,往往需要做大量的數據搬移工作,效率很低。
動態數組功能實現
1.數組初始化
考慮到擴容時數據搬移可能會發生的內存泄露,博主這里采用兩只手的原則,即設定一個內存標志位 ItemsFlag 。當 ItemsFlag = 0,using preitems;當 ItemsFlag = 1,using items。下文擴容部分有具體實現。默認數組容量10。
enum { MAX = 10 }; explicit GenericArray(int ss = MAX); template<class T> GenericArray<T>::GenericArray(int ss) : capacity(ss),counts(0) { itemsFlag = 0; preitems = new T[capacity]; items = nullptr; }
2.析構函數
釋放內存。
template<class T> GenericArray<T>::~GenericArray() { if (preitems != nullptr) delete[]preitems; if (items != nullptr) delete[]items; }
3.檢查下標
檢查要操作的下標是否在數組容量范圍內。
template<class T> bool GenericArray<T>::checkIndex(int index) { if (index < 0 || index >= capacity) { int cap = capacity - 1; cout << "Out of the range! Please ensure the index be in 0 ~ " << cap << '\n'; return false; } return true; }
4.獲取元素數目和容量、判斷數組空和滿
int count()const { return counts; } int getCapacity()const { return capacity; } bool isEmpty()const { return counts == 0; } bool isFull()const { return counts >= capacity; }
5.取索引對應值、按索引修改值、打印輸出、是否包含某值
template<class T> T GenericArray<T>::get(int index) { if (!itemsFlag) return preitems[index]; else return items[index]; } void GenericArray<T>::set(int index, T elem) { if(checkIndex(index)) { if (!itemsFlag) preitems[index] = elem; else items[index] = elem; return; } } template<class T> void GenericArray<T>::printArray()const { for (int i = 0; i < counts; i++) if (!itemsFlag) cout << preitems[i] << '\t'; else cout << items[i] << '\t'; cout << '\n'; return; } template<class T> bool GenericArray<T>::contains(T arr) { for (int i = counts - 1; i >= 0; i--) if (!itemsFlag) { if (arr == preitems[i]) return true; } else { if (arr == items[i]) return true; } return false; }
6.查找某值下標、刪除某值
查找某值的下標時,要考慮到該值在數組中是否重復,所以博主用了一個結構體 findArrIndex 來存儲該值重復的次數和對應的下標。
struct findArrIndex { int numIndex; int *findIndex; }; template<class T> void GenericArray<T>::find(T arr, findArrIndex *ps) { ps->findIndex = new int[counts]; ps->numIndex = 0; for (int i = 0, j = 0; i < counts; i++, j++) if (!itemsFlag) { if (arr == preitems[i]) { (ps->findIndex)[j] = i; (*ps).numIndex++; cout << i << '\t'; } } else if (arr == items[i]) { (ps->findIndex)[j] = i; (*ps).numIndex++; cout << i << '\t'; } cout << '\n'; return; } template<class T> void GenericArray<T>::removeElement(findArrIndex *ps) { for (int i = ps->numIndex; i > 0; i--) remove((ps->findIndex)[i - 1]); delete[](ps->findIndex); } template<class T> void GenericArray<T>::set(int index, T elem) { if(checkIndex(index)) { if (!itemsFlag) preitems[index] = elem; else items[index] = elem; return; } }
7.擴容
添加數據操作時需判斷數組容量是否足夠,若不夠需考慮擴容。
template<class T> void GenericArray<T>::renewCapacity() { cout << "The array's capacity is small! Renew capacity.\n"; if (capacity < 1000) capacity = capacity << 1; else capacity = capacity >> 1 + capacity; if (!itemsFlag) { itemsFlag = 1; items = new T[capacity]; for (int i = 0; i<counts; i++) *(items + i) = *(preitems + i); //items[i]=proitems[i]; //cout << items << '\n'; //cout << preitems << '\n'; delete[]preitems; preitems = nullptr; } else { itemsFlag = 0; preitems = new T[capacity]; for (int i = 0; i<counts; i++) *(preitems + i) = *(items + i); delete[]items; items = nullptr; } }
8.添加數據:數組添加數據包括按索引下標插值、數組頭插值、數組尾插值。實質上后兩種都可以通過調用按索引下標插值函數實現。前文也提到過,數組添加操作中復雜的是大量的數據搬移工作:將某個元素按索引下標插入到數組第k個位置,需要將k ~ n部分的元素向后搬移一位,然后插入元素,更新元素數目。若插入到數組尾,時間復雜度O(1);插入到數組頭,時間復雜度O(n);插入的平均時間復雜度為(1+2+…+n)/n = O(n)。
另外,還有一個優化問題:若數組是無序數組,則插入時不需要搬移數據:若將某個元素插入到數組第k個位置,首先將該位置的元素移動到數組末尾,然后將待插入元素插入到第k個位置,時間復雜度O(1)。
template<class T> void GenericArray<T>::add(int index, T elem) { if (isFull()) { cout << "Array is full!" << '\n'; renewCapacity(); } if (checkIndex(index)) if(!itemsFlag) { for (int i = counts; i > index; i--) preitems[i] = preitems[i - 1]; preitems[index] = elem; } else { for (int i = counts; i > index; i--) items[i] = items[i - 1]; items[index] = elem; } counts++; return; } template<class T> void GenericArray<T>::addFirst(T elem) { add(0, elem); } template<class T> void GenericArray<T>::addLast(T elem) { add(counts, elem); }
9.刪除數據:數組刪除數據包括按索引下標刪除、數組頭刪除、數組尾刪除。實質上后兩種都可以通過調用按索引下標刪除函數實現。與前文類似,數組刪除操作中復雜的也是大量的數據搬移工作:按索引下標將某個元素刪除,需要將k+1 ~ n部分的元素向前搬移一位,更新元素數目。若刪除數組尾,直接元素數目減一即可,時間復雜度O(1);刪除數組頭,時間復雜度O(n);刪除的平均時間復雜度(1+2+…+n)/n = O(n)。
另外,有一個優化問題:如果想多次刪除數組中的值,可以先對要刪除的值做好標記,做完標記后一次刪除,這樣就大大減少了搬移的次數。
template<class T> T GenericArray<T>::remove(int index) { if (!isEmpty()) { if (checkIndex(index)) { if (!itemsFlag) { T temp = preitems[index]; for (int i = index+1; i < counts; i++) preitems[i - 1] = preitems[i]; counts--; return temp; } else { T temp = items[index]; for (int i = index + 1; i < counts; i++) items[i - 1] = items[i]; counts--; return temp; } } } else { cout << "Array is empty!" << '\n'; return -1; } } template<class T> T GenericArray<T>::removeFirst() { return remove(0); } template<class T> T GenericArray<T>::removeLast() { return remove(counts - 1); }
好啦,基本上就這么多了。
最后總結一下,多看源碼還是很重要的。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。