數據結構與算法——線性表(數組描述)

前言

  1. 表ADT常用的描述方法有兩種:數組描述鏈式描述,在STL中分別有容器vectorlist與之對應。本文重點討論線性表的數組描述,通過利用C++語言從零開始實現數組描述的線性表,對其進行學習(所使用的函數名和簽名與STL代碼相同)。
  2. 線性表也稱有序表,其每一個實例均爲元素的一個有序集合。元素被看做原子,其本身的結構與線性表的結構無關。線性表除了先後關係的有序性之外,不再有其他關係。
  3. 表ADT
    在這裏插入圖片描述

線性表(數組描述)C++實現

1、抽象類linearList

template<class T>
class linearList
{
public:
	virtual ~linearList() {};
	virtual bool empty() const = 0;
	// 判斷是否爲空
	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;
	//把線性表插入輸出流
};

注:抽象類不能實例化,但是數組表和鏈表均繼承自抽象類linearList。

2、數組類

2.1 數組動態調整實現
創建一個數組類,以實現抽象數據類型linearList,必須選擇element的類型和數組長度。模板類可以解決第一個問題,動態數組解決第二個問題。
改變一個數組長度的代碼實現:

template<class T>
void changeLength1D(T*& a, int oldLength, int newLength)
{
	if (newLength < 0)
		throw illegalParameterValue("new length must be >= 0");

	T* temp = new T[newLength];              // new array
	int number = min(oldLength, newLength);  // number to copy
	copy(a, a + number, temp);
	delete[] a;                             // deallocate old memory
	a = temp;
}

2.2 數組類arrayList實現
arrayList是linearList的派生類,必須實現linearList中的所有方法,還可包含抽象類中沒有的方法:capacity給出element的長度、checkIndex確定一個元素在0~listSize-1內的索引。

template<class T>
class arrayList : public linearList<T>
{
public:
	// 構造函數、複製函數、析構函數
	arrayList(int initialCapacity = 10);
	arrayList(const arrayList<T>&);
	~arrayList() { delete[] element; }

	// ADT 方法
	bool empty() const { return listSize == 0; }
	int size() const { return listSize; }
	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;

	// 其他方法
	int capacity() const { return arrayLength; }

protected:
	void checkIndex(int theIndex) const;
	// theIndex無效則拋出異常
	T* element;            // 存儲線性表元素的一維數組
	int arrayLength;       //一維數組的容量
	int listSize;          // 線性表元素個數
};

arrayList類方法的實現代碼:

template<class T>
arrayList<T>::arrayList(int initialCapacity)
{// Constructor.
	if (initialCapacity < 1)
	{
		ostringstream s;
		s << "Initial capacity = " << initialCapacity << " Must be > 0";
		throw illegalParameterValue(s.str());
	}
	arrayLength = initialCapacity;
	element = new T[arrayLength];
	listSize = 0;
}

template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList)
{// Copy constructor.
	arrayLength = theList.arrayLength;
	listSize = theList.listSize;
	element = new T[arrayLength];
	copy(theList.element, theList.element + listSize, element);
}

template<class T>
void arrayList<T>::checkIndex(int theIndex) const
{// Verify that theIndex is between 0 and listSize - 1.
	if (theIndex < 0 || theIndex >= listSize)
	{
		ostringstream s;
		s << "index = " << theIndex << " size = " << listSize;
		throw illegalIndex(s.str());
	}

}

template<class T>
T& arrayList<T>::get(int theIndex) const
{// Return element whose index is theIndex.
 // Throw illegalIndex exception if no such element.
	checkIndex(theIndex);
	return element[theIndex];
}

template<class T>
int arrayList<T>::indexOf(const T& theElement) const
{// Return index of first occurrence of theElement.
 // Return -1 if theElement not in list.

   // search for theElement
	int theIndex = (int)(find(element, element + listSize, theElement)
		- element);

	// check if theElement was found
	if (theIndex == listSize)
		// not found
		return -1;
	else return theIndex;
}

template<class T>
void arrayList<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.
 // Throw illegalIndex exception if no such element.
	checkIndex(theIndex);

	// valid index, shift elements with higher index
	copy(element + theIndex + 1, element + listSize,
		element + theIndex);

	element[--listSize].~T(); // invoke destructor
}

template<class T>
void arrayList<T>::insert(int theIndex, const T & theElement)
{// Insert theElement so that its index is theIndex.
	if (theIndex < 0 || theIndex > listSize)
	{// invalid index
		ostringstream s;
		s << "index = " << theIndex << " size = " << listSize;
		throw illegalIndex(s.str());
	}

	// valid index, make sure we have space
	if (listSize == arrayLength)
	{// no space, double capacity
		changeLength1D(element, arrayLength, 2 * arrayLength);
		arrayLength *= 2;
	}

	// shift elements right one position
	copy_backward(element + theIndex, element + listSize,
		element + listSize + 1);

	element[theIndex] = theElement;

	listSize++;
}

template<class T>
void arrayList<T>::output(ostream & out) const
{// Put the list into the stream out.
	copy(element, element + listSize, ostream_iterator<T>(cout, "  "));
}

// overload <<
template <class T>
ostream& operator<<(ostream & out, const arrayList<T> & x)
{
	x.output(out); return out;
}

3、總結

  • 上述實現了最基本的arrayList類,可以爲其添加迭代器以適用於STL的迭代器算法,這個迭代器被定義爲類arrayList的公有成員。
  • vector描述:STL的vector沒有一個構造函數與arrayList的構造函數等價,也沒有名爲get, indexOf, output等方法,可以定義一個vectorList類,用vector描述線性表,其方法簽名和操作與linearList相同。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章