数据结构 顺序表与链表(一)

线性结构(Linear Structure)—— List、Stack、Queue

线性结构反映节点之间的逻辑关系是一对一的

可表示为:\left ( a_{1},...,a_{i-1},a_{i},a_{i+1},...,a_{n} \right )

 a_{1} : Head;  a_{n} : Tail;  a_{i-1}a_{i} 的直接前驱; a_{i+1}a_{i}的直接后继;n = 0时为空表;

线性表(linear list):是具有相同特性的数据元素的一个有限序列

ADT(Abstract Data Type):抽象数据类型,是哟个实现包括储存元素的存储结构以及实现基本操作的算法。

这里,数据类型的定义和它的实现是分开的,如抽象类(virtual)、类模板(template)。

an ADT for a list:

(这是一个抽象类的类模板,因此继承它的所有类和类模板都必须实现它的全部抽象方法) 

template <typename E> class List {		// the ADT for a list
private: 
	void operator =(const List&) {}		// Protect assignment 
	List(const List&) {}			// Protect copy constructor 
public: 
	List() {}			        // Default constructor 
	virtual ˜List() {}			// Base destructor

     	virtual void clear() = 0;     
	virtual void insert(const E& item) = 0;
        virtual void append(const E& item) = 0;
	virtual E remove() = 0;
	virtual void moveToStart() = 0;
	virtual void moveToEnd() = 0;
	virtual void prev() = 0;
	virtual void next() = 0;
	virtual int length() const = 0;
	virtual int currPos() const = 0;
	virtual void moveToPos(int pos) = 0;
	virtual const E& getValue() const = 0; 
};

 遍历一个list / 查找一个元素:

bool find(List<int>& L, int K) { 
	int it; 
	for (L.moveToStart(); L.currPos()<L.length(); L.next()) { 
		it = L.getValue(); 
		if (K == it) 
			return true;	 
	} return false; 
}

两种典型的List的实现

1. 顺序表(Array-based List)——— 在程序中,叫做“AList”, 继承于class List

把list中的所有元素按照顺序存储方法,依次存储到存储器中一片连续的存储空间中。

在List对象被创建时就要知道它的大小:n*sizeof(ElemType)

先上代码,讲解在后:

template <typename E>  class AList : public List<E> {
private:
	int maxSize;	    // Maximum size of list 
	int listSize;       // Number of list items now 
	int curr;	    // Position of current element 
	E* listArray;	    // Array holding list elements
public:
	AList(int size = defaultSize) {		// Constructor 
		maxSize = size;
		listSize = curr = 0;
		listArray = new E[maxSize];
	}
	˜AList() { delete[] listArray; }        // Destructor

	void clear() {			// Reinitialize the list 
		delete[] listArray;	        // Remove the array 
		listSize = curr = 0;	        // Reset the size 
		listArray = new E[maxSize];     // Recreate array 
	}

	void insert(const E& it) {		// Insert "it" at current position 
		assert(listSize < maxSize, "List capacity exceeded"); //assert:如果不满足前面的条件,则返回这串文字
		for (int i = listSize; i > curr; i--)	    // Shift elements up 
			listArray[i] = listArray[i - 1];	// to make room 
		listArray[curr] = it;
		listSize++;			// Increment list size 
	}
	void append(const E& it) {		// Append "it" 
		assert(listSize < maxSize, "List capacity exceeded");
		listArray[listSize++] = it;
	}

	
	E remove() {	             // Remove and return the current element. 
		assert((curr >= 0) && (curr < listSize), "No element");
		E it = listArray[curr];		// Copy the element 
		for (int i = curr; i < listSize - 1; i++)	// Shift them down 
			listArray[i] = listArray[i + 1];
		listSize--;			// Decrement size 
		return it;
	}

	void moveToStart() { curr = 0; }	    // Reset position 
	void moveToEnd() { curr = listSize; }	    // Set at end 
	void prev() { if (curr != 0) curr--; }	        // Back up
	void next() { if (curr < listSize) curr++; }	// Next
 
	int length() const { return listSize; }		// Return list siz
	int currPos() const { return curr; }		// Return current position 								 
	void moveToPos(int pos) {	    // Set current list position to "pos"
		assert ((pos>=0)&&(pos<=listSize), "Pos out of range"); 
		curr = pos; 
	}
	const E& getValue() const {	    // Return current element 
		assert((curr>=0)&&(curr<listSize),"No current element"); 
		return listArray[curr]; 
	} 
};

Insert方法:时间复杂度与 ListSize和插入的位置都有关,最好\mathit{O}\left ( 1 \right ),最坏\mathit{O}\left ( n\right )

                   平均:共有(n+1)个位置可以插入元素,需要移动0~n个元素:平均n/2

                    Insert方法的时间复杂度为:\mathit{O}\left ( n\right )

remove方法:原理同Insert方法,时间复杂度为\mathit{O}\left ( n\right )

除Insert、remove、constructor、destructor、clear外,其他方法时间复杂度为\mathit{O}\left ( 1\right )

顺序存储结构的问题:存储空间分配不灵活;运算的空间复杂度高

猜你喜欢

转载自blog.csdn.net/qq_42182367/article/details/82729693