線性表類型的實現——順序映像(順序存儲結構),順序表上的基本操作(初始化、查詢、插入、刪除)

線性表的順序存儲結構: 用一組地址連續的存儲單元依次存放線性表中的數據元素。
它是實現線性表最簡單的方法。

在這裏插入圖片描述

順序存儲結構的C語言描述:
對於線性表來說,可以開闢一個一維數組空間,來存儲線性表的數據元素。由於線性表本身的長度是可變的,所以需要一個參量來指示當前的長度(length,對應線性表的邏輯結構)。而對於數組來說,它應該有一個當前分配的存儲量(listsize,對應線性表的存儲結構)。
另外,順序存儲結構俗稱順序表。

#define LIST_INIT_SIZE 80  //線性表存儲空間的初始分配量
#define LISTINCREMENT 10  //線性表存儲空間的分配增量
typedef struct
{
  ElemType *elem;  //存儲空間基址
  int length;  //當前長度
  int listsize; //當前分配的存儲容量;以sizeof(ElemType)爲單位
}SqList; //俗稱 順序表

在順序表表示的情況下進行的基本操作:
【初始化操作】

//構造一個空的線性表
Status InitList_Sq(SqList &L)
{
	//給線性表的數據元素開闢一個一維的數組空間
	L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
	
	if (!L.elem) exit(OVERFLOW);
	L.length = 0;//初始時線性表是個空表,長度爲0
	L.listsize = LIST_INIT_SIZE;//給定線性表的存儲空間的大小
	return OK;
}//InitList_Sq

【查詢操作】

//在線型表L中找到第一個與e滿足特定關係的數據元素的位序(查詢操作)
int LocateElem_Sq(SqList L, ElemType e, Status(*compare)(ElemType, ElemType))
{
	i = 1;				//i的初值爲第1個元素的位序
	p = L.elem;			//p的初值爲第1個元素的存儲位置
	while (i <= L.length && !(*compare)(*p++, e)) ++i;
	if (i <= L.length) return i;
	else return 0;
}//LocateElem_Sq

這個操作的時間複雜度爲:O(ListLength(L))O(ListLength(L)),其中,ListLength(L)ListLength(L)表示表長。

【插入操作】
插入元素時,線性表的邏輯結構發生了什麼變化?很顯然,(a1, … ai-1, ai, …, an)改變爲(a1, … ai-1, e, ai, …, an),這個變化體現在兩方面:(1)有序對<ai-1, ai>變成了有序對<ai-1, e>和<e, ai>;(2)長度增1。
這是相當於前i-1個元素(a1, … ai-1)不變,後n-i+1個元素(ai, …, an)後移一位,最終長度增1。

//在線性表中第pos個位置上插入元素e
Status ListInsert_Sq(SqList &L, int pos, ElemType e)
{
    //算法的健壯性
	if (pos<1 || pos>L.length + 1) return ERROR;  //插入位置不合法
	if (L.length >= L.listsize)  //當前存儲空間已滿,增加分配
	{
		newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));//數組空間的再分配
		if (!newbase) exit(OVERFLOW);//存儲分配失敗
		L.elem = newbase;			//新基址
		L.listsize += LISTINCREMENT;//增加存儲容量
	}
   
   //算法的主題
	q = &(L.elem[pos - 1]);     //q指示插入位置
	for (p = &(L.elem[L.length - 1]); p >= q; --p)
		*(p + 1) = *p;//插入位置及之後的元素右移
	*q = e;   //插入e
	++L.length;//表長增1
	return OK;		
}

在這裏插入圖片描述

在第i個位置插入元素,移動元素的個數爲ni+1n-i+1
這個算法的時間複雜度爲:O(ListLength(L))O(ListLength(L))
也可以考慮平均的情況:
假設在第i個元素之前插入的概率爲pi,則在長度爲n的線性表中插入一個元素,所需移動元素次數的期望值爲:
Eis=i=1n+1pi(ni+1)E_{is}=∑_{i=1}^{n+1}p_i (n-i+1)
若假定在線性表中任何一個位置上進行插入的概率都是相等的,則移動元素的期望值爲:
Eis=1n+1i=1n+1(ni+1)=n2E_{is}=\frac{1}{n+1}∑_{i=1}^{n+1}(n-i+1)=\frac{n}{2}
爲表長的一半。

【刪除操作】
刪除元素時,線性表的邏輯結構發生什麼變化?很顯然,(a1, … ai-1, ai, ai+1, …, an)改變爲(a1, … ai-1, ai+1, …, an),這個變化也體現在兩個方面,與插入操作相反:(1)有序對<ai-1, ai>和<ai, ai+1>變成了有序對<ai-1, ai+1>;(2)表長減1。
這是相當於前i-1個元素(a1, … ai-1)不變,後n-i個元素(ai+1, …, an)前移一位,最終長度減1。

//在線性表L中刪除第pos個位置上的元素,並將刪除的元素賦值給e
Status ListDelete_Sq(SqList &L, int pos, ElemType &e)
{
	//算法的健壯性
	if ((pos < 1) || (pos > L.length))  return ERROR;	//刪除位置不合法

	//算法的主題
	p = &(L.elem[pos - 1]); //p爲被刪除元素的位置
	e = *p;   //被刪除元素的位置賦給e
	q = L.elem + L.length - 1;//表尾元素的位置
	for (++p; p <= q; ++p)
		*(p - 1) = *p;     //被刪除元素之後的元素前移
	--L.length;		//表長減1
	return OK;
}//ListDelete_Sq

時間複雜度是對於問題規模而言的,這時候需要忽略刪除元素這個因素。
所以,這個算法的時間複雜度爲:O(ListLength(L))O(ListLength(L))
也可以考慮平均的情況:
假設刪除第i個元素的概率爲qi,則在長度爲n的線性表中刪除一個元素,所需移動元素次數的期望值爲:
Edl=i=1nqi(ni)E_{dl}=∑_{i=1}^{n}q_i (n-i)
若假定在線性表中任何一個位置上進行插入的概率都是相等的,則移動元素的期望值爲:
Edl=1ni=1n(ni)=n12E_{dl}=\frac{1}{n}∑_{i=1}^{n}(n-i)=\frac{n-1}{2}
大致也爲表長的一半。

對順序表的總結:
【優點】
可以對每個數據元素進行隨機的存取,它的表長是顯值。
【缺點】
在插入和刪除數據元素的時候要進行元素的移動。每進行一次插入或刪除,都要大致移動表的一半的元素。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章