1. 程式人生 > >筆記四:線性表——陣列描述

筆記四:線性表——陣列描述

線性表

  • 定義:有序表,元素按照一定順序形成的有序集合

  • 陣列描述的線性表:

    1、程式碼:

#pragma warning(disable:4996)

#include<iostream>
#include<iterator>
#include<algorithm>
using namespace std;

typedef struct{
    int a;
    int b;
} Mytype;

template<typename T>
class linearList
{
public:
    virtual ~linearList() {};                  //解構函式
virtual bool empty() const = 0; //返回true,當且僅當線性表為空 virtual int size() const = 0; //返回線性表的元素個數 virtual T& get(int theIndex) const = 0; //返回索引為theIndex的元素 virtual int indexOf(const T& theElement) const = 0; //返回元素theElement第一次出現時的索引 virtual void erase(int theIndex) = 0
; //刪除索引為theIndex的元素 virtual void insert(int theIndex, const T& theElement) = 0; //把theElement插入線性表中索引為theIndex的位置 virtual void output(ostream& out) const = 0; //把線性表插入的輸出流out }; template<typename T> class arrayList : public linearList<T> { public
: //建構函式、複製建構函式、解構函式 arrayList(int initialCapacity = 10); arrayList(const arrayList<T>&); ~arrayList() { delete[] element; } //ADT方法 bool empty() const; int size() const; T& get(int theIndex) const; int indexOf(const T& theElement) const; void erase(int theIndex); void insert(int theIndex, const T& theElement); void output(ostream& out) const; public: void changeLength1D(T*& a, int oldLength, int newLength); friend ostream& operator<<(ostream& out, const arrayList<T>& x); void checkIndex(int theIndex) const; private: int listSize; //線性表的元素個數 int arrayLength; //一維陣列的容量 T* element; //儲存線性表元素的一維陣列 }; template<typename T> arrayList<T>::arrayList(int initialCapacity) {//建構函式 arrayLength = initialCapacity; element = new T[arrayLength]; listSize = 0; } template<typename T> arrayList<T>::arrayList(const arrayList<T>& theList) {//複製建構函式 arrayLength = theList.arrayLength; listSize = theList.listSize; element = new T[arrayLength]; copy(theList.element, theList.element + listSize, element); } template<typename T> bool arrayList<T>::empty() const { return (listSize == 0 ? true : false); } template<typename T> int arrayList<T>::size() const { return listSize; } template<typename T> T& arrayList<T>::get(int theIndex) const { checkIndex(theIndex); return element[theIndex]; } template<typename T> int arrayList<T>::indexOf(const T& theElement) const { //指向theElement的指標與陣列首指標的差值 int theIndex = (int)(find(element, element + listSize, theElement) - element); return (theIndex == listSize ? -1 : theIndex); } template<typename T> void arrayList<T>::erase(int theIndex) { checkIndex(theIndex); //將theIndex後面的元素依次前移一位,通過佔據theIndex元素的位置將其覆蓋 copy(element + theIndex + 1, element + listSize, element + theIndex); element[--listSize].~T(); //刪除最後一個元素,避免重複 } template<typename T> void arrayList<T>::insert(int theIndex, const T& theElement) { //theIndex不合法 if (theIndex <0 || theIndex > listSize) { cout << "元素插入的theIndex下標不合理! "; exit(-1); } //有效索引,判斷陣列是否已滿 if (listSize == arrayLength) { //增加陣列容量 changeLength1D(element, arrayLength, arrayLength * 2); arrayLength = arrayLength * 2; //修改陣列容量值 } copy_backward(element + theIndex, element + listSize, element + listSize + 1); element[theIndex] = theElement; ++listSize; } template<typename T> void arrayList<T>::changeLength1D(T*& a, int oldLength, int newLength) { //判斷新的容量是否合法 if (newLength < 0) { cout << "錯誤:newLength 小於 0!"; exit(-1); } T *tmp = new T[newLength]; int number = min(oldLength, newLength); //複製的元素的數量判斷 copy(a, a + number, tmp); //元素複製 a = tmp; } template<typename T> ostream& operator<<(ostream& out, const arrayList<T>& x) { x.output(out); return out; } template<typename T> void arrayList<T>::output(ostream& out) const { //把線性表插入輸出流 copy(element, element + listSize, ostream_iterator<T>(cout, " ")); } template<typename T> void arrayList<T>::checkIndex(int theIndex) const { if (theIndex < 0 || theIndex >= listSize) { cout << "錯誤:theIndex 不合法!"; exit(-1); } } int main(int argc, char * argv[]) { arrayList<int> aL(10); //測試insert函式 aL.insert(0, 5); aL.insert(1, 4); aL.insert(2, 3); aL.insert(3, 2); aL.insert(4, 1); //測試output函式 cout << "初始線性表為:"; aL.output(cout); cout << endl; cout << "初始線性表的大小為:" << aL.size()<<endl; //測試erase函式 cout << "刪除theIndex = 2的元素後線性表為:"; aL.erase(2); aL.output(cout); cout << " 大小size: " << aL.size() << endl; //測試insert函式 aL.insert(0, 0); cout << "在theIndex = 0的位置插入元素0後,線性表為:"; aL.output(cout); cout << " 大小size: " << aL.size() << endl; //測試indexOf函式 cout << "元素值為5的下標是:" << aL.indexOf(5) << endl; //測試get函式 cout << "下標為1的元素是:" << aL.get(1) << endl; return 0; }

2、執行:

這裡寫圖片描述

  • 擴充套件:

    • 純虛擬函式:為後代型別提供了可以覆蓋的介面、但是該類中的版本絕不會呼叫,且不允許建立物件。在函式形參表後面寫上 = 0 用以指定純虛擬函式。virtual fun() = 0 ;

    • 抽象基類:含有(或繼承)一個或多個純虛擬函式的類。不能建立例項物件。

    • 過載操作符
      1、過載操作符必須具有一個類型別或列舉型別的運算元。
      2、一般將算數和關係操作符定義為非成員函式,而將賦值操作符定義為成員函式.
      3、作為類成員的過載函式,其形參比運算元目少1,因為第一個運算元為隱含的this形參Sale_item& operator+=(const Sale_item&);
      4、操作符定義為非成員函式時,通常設定為友元friend ostream& operator<<(ostream& out, const arrayList<T>& x);

    • 建構函式與複製建構函式
      1、建構函式:保證每個物件的資料成員具有合適的初始值A::A(const int& x) : a(0), b(x) {};
      2、複製建構函式:只有單個形參,且該形參是對本類型別的引用(常用const修飾)。

    • 解構函式與虛解構函式
      1、解構函式:完成所需的資源回收,作為類建構函式的補充。解構函式無法過載。
      2、許多類不需要顯示解構函式,尤其是具有建構函式的類不一定要定義自己的建構函式。如果類需要解構函式,則它也需要賦值操作符和複製建構函式——三法則。
      3、動態分配的記憶體只有在指向該物件的指標被刪除時才撤銷,如果沒有刪除指向動態物件的指標,則不會執行該物件的解構函式,物件就一直存在,從而導致記憶體洩露。
      4、賦值操作符:1)過載的賦值操作符Sale_item& operator=(const Sale_item&);,2)合成賦值操作符——逐個成員賦值。
      5、賦值操作符與複製建構函式的呼叫區別:如果物件在宣告的同時,將一個已存在的物件賦值給它,則呼叫複製建構函式;如果物件已經存在,再將另一個已存在的物件賦給它,則呼叫賦值操作符。
      3、虛解構函式:如果刪除基類指標,則需執行基類解構函式,若物件是派生型別,則不需要定義該行為。為了保證執行適當的解構函式,基類中的解構函式必須為虛解構函式。(即使解構函式沒有工作要做,繼承層次的根類也應該定義一個虛解構函式。

    • copy()與copy_backward(): copy()函式實現元素左移功能,copy_backward()實現元素右移功能。