1. 程式人生 > >順序儲存線性表的C++實現——嚴蔚敏版《資料結構》

順序儲存線性表的C++實現——嚴蔚敏版《資料結構》

      因為最近在拿嚴蔚敏版的《資料結構》複習相關知識,所以就通過動手實現來加深理解,在這裡與大家分享。話不多說,直接上程式碼,註釋比較詳細,就不另外解說了。

     首先是List_Sq.h,這裡使用了類模板以及函式模板,便於將該順序線性表使用在不同的基本資料型別。

#ifndef __List_Sq_H__
#define __List_Sq_H__

#include<iostream>
#include<cstdlib>

using namespace std;

const int LIST_INIT_SIZE = 100; //線性表的初始空間分配量 
const int LIST_INCREMENT = 10;  // 線性表儲存空間的分配增量

const int OVER_FLOW = -2; // 記憶體分配失敗狀態程式碼

// 動態分配順序儲存結構的線性表 
template <class T>
struct SqList{
	T *elem; 		// 儲存空間基址 
	int length; 	// 當前長度 
	int listsize; 	// 當前分配的儲存容量 
};

template <class T>
class List_Sq
{
public:
	void InitList_Sq(SqList<T> &L);				// 構造一個空的線性表L
	void DestroyList_Sq(SqList<T> &L); 			// 銷燬線性表L
	bool ClearList_Sq(SqList<T> &L); 			// 將L重置為空表
	bool ListEmpty_Sq(SqList<T> L); 			// 若L為空表,返回true,否則返回false
	int ListLength_Sq(SqList<T> L); 			// 返回L中資料元素的個數
	bool GetElem_Sq(SqList<T> L, int i, T &e);  // 用e返回L中第i個數據元素的值
	int LocateElem_Sq(SqList<T> L, T e, bool(*compare)(T e1, T e2));
	// 返回L中第1個與e滿足關係compare()的資料元素的位序。
	// 若這樣的資料元素不存在,則返回值為0
	bool PriorElem_Sq(SqList<T> L, T cur_e, T &pre_e);
	// 若cur_e是L中的資料元素,且不是第一個,則用pre_e返回它的前驅
	// 否則操作失敗,pre_e無定義
	bool NextElem_Sq(SqList<T> L, T cur_e, T &next_e);
	// 若cur_e是L中的資料元素,且不是最後一個,則用pre_e返回它的後繼 
	// 否則操作失敗,pre_e無定義		
	bool ListInsert_Sq(SqList<T> &L, int i, T e);
	// 在L中第i個位置之前插入新的資料元素e,L的長度加1
	bool ListDelete_Sq(SqList<T> &L, int i, T &e);
	// 刪除L的第i個數據元素,並用e返回其值,L的長度減1
	void output(SqList<T> L);					// 輸出線性表中的所有元素 
};

template <class T>
void List_Sq<T>::InitList_Sq(SqList<T> &L)
{
	L.elem = (T *)malloc(LIST_INIT_SIZE * sizeof(T));
	if (!L.elem)
		exit(OVER_FLOW);		 // 儲存分配失敗 
	L.length = 0;				 // 空表長度為0
	L.listsize = LIST_INIT_SIZE; // 初始儲存容量 
}

template <class T>
void List_Sq<T>::DestroyList_Sq(SqList<T> &L)
{
	if (L.elem != NULL)
		free(L.elem);			 // 釋放儲存空間 
}

template <class T>
bool List_Sq<T>::ClearList_Sq(SqList<T> &L)
{
	if (L.elem == NULL)			// 線性表不存在 
		return false;
	else {
		free(L.elem);			// 釋放並重新分配儲存空間 
		L.elem = (T *)malloc(LIST_INIT_SIZE * sizeof(T));
		L.length = 0;
		return true;
	}
}

template <class T>
bool List_Sq<T>::ListEmpty_Sq(SqList<T> L)
{
	if (0 == L.length)
		return true;
	else
		return false;
}

template <class T>
int List_Sq<T>::ListLength_Sq(SqList<T> L)
{
	return L.length;
}

template <class T>
bool List_Sq<T>::GetElem_Sq(SqList<T> L, int i, T &e)
{
	if (i < 1 || i > L.length)		 // i不在合法範圍內 
		return false;
	else {
		e = L.elem[i - 1];
		return true;
	}
}

template <class T>
int List_Sq<T>::LocateElem_Sq(SqList<T> L, T e, bool(*compare)(T e1, T e2))
{ // 在順序線性表L中查詢第一個值與e滿足compare()的元素的位序 
  // 若找到,則返回其在L中的位序,否則返回0
	int i = 1;			// i的初值為第一個元素的位序
	T *p = L.elem;		// p的初值為第一個元素的儲存位置
	while (i <= L.length && !(*compare)(*p++, e))
		++i;
	if (i <= L.length)
		return i;
	else
		return 0;
}

template <class T>
bool List_Sq<T>::PriorElem_Sq(SqList<T> L, T cur_e, T &pre_e)
{
	T *p = L.elem, *q = L.elem + L.length - 1; // p初值為第一個元素的儲存位置,q為最後一個元素的儲存位置 
	for (p; p <= q; ++p){
		if (*p == cur_e && p != L.elem) { // cur_e是線性表中的資料元素且不是第一個 
			pre_e = *(--p);
			return true;
		}
	}
	return false;
}

template <class T>
bool List_Sq<T>::NextElem_Sq(SqList<T> L, T cur_e, T &next_e)
{
	T *p = L.elem, *q = L.elem + L.length - 1;
	for (p; p < q; ++p){ // cur_e是線性表中的資料元素且不是最後一個 
		if (*p == cur_e) {  
			next_e = *(++p);
			return true;
		}
	}
	return false;
}

template <class T>
bool List_Sq<T>::ListInsert_Sq(SqList<T> &L, int i, T e)
{
	if (i < 1 || i > L.length + 1) // i值不合法 
		return false;
	if (L.length >= L.listsize) { // 當期儲存空間已滿,增加分配		
		T *newbase = (T *)realloc(L.elem, (L.listsize + LIST_INCREMENT) * sizeof(T));
		if (!newbase)
			exit(OVER_FLOW);		  // 儲存分配失敗
		L.elem = newbase;			  // 新基址
		L.listsize += LIST_INCREMENT; // 增加儲存容量 
	}
	T *q = &(L.elem[i - 1]);		  // q為插入位置
	for (T *p = &(L.elem[L.length - 1]); p >= q; --p)
		*(p + 1) = *p;				  // 插入位置及之後的元素右移
	*q = e;		// 插入e
	++L.length; // 表長增1
	return true;
}

template <class T>
bool List_Sq<T>::ListDelete_Sq(SqList<T> &L, int i, T &e)
{
	if (i < 1 || i > L.length) // i值不合法 
		return false;
	T *p = &(L.elem[i - 1]);	  // p為被刪除元素的位置
	e = *p;						  // 被刪除元素的值賦給e
	T *q = L.elem + L.length - 1; // 表尾元素的位置
	for (++p; p <= q; ++p)
		*(p - 1) = *p;	// 被刪除元素之後的元素左移
	--L.length;			// 表長減1
	return true;
}

template <class T>
void List_Sq<T>::output(SqList<T> L)
{
	T *p = L.elem, *q = L.elem + L.length - 1;
	for (p; p <= q; ++p)
		cout << *p << " ";
	cout << endl;
}

template <class T>
bool compare(T e1, T e2)
{ // 比較函式,這裡以相等為例 
	if (e1 == e2)
		return true;
	else
		return false;
}

template <class T>
void MergeList_Sq(SqList<T> La, SqList<T> Lb, SqList<T> &Lc)
{ // 已知順序線性表La和Lb的元素按值非遞減排列
  // 歸併La和Lb得到新的順序線性表Lc,Lc的元素也按值非遞減排列
	T *pa = La.elem, *pb = Lb.elem;
	Lc.listsize = Lc.length = La.length + Lb.length;
	T *pc = Lc.elem = (T *)malloc(Lc.listsize * sizeof(T));
	if (!Lc.elem)
		exit(OVER_FLOW);					 // 儲存分配失敗
	T *pa_last = La.elem + La.length - 1;
	T *pb_last = Lb.elem + Lb.length - 1;
	while (pa <= pa_last && pb <= pb_last) { // 歸併 
		if (*pa <= *pb)
			*pc++ = *pa++;
		else
			*pc++ = *pb++;
	}
	while (pa <= pa_last)					 // 插入La的剩餘元素 
		*pc++ = *pa++;
	while (pb <= pb_last)					 // 插入Lb的剩餘元素 
		*pc++ = *pb++;
}

#endif // !__List_Sq__H

      接下來是測試程式碼main.cpp。

#include "List_Sq.h"

int main()
{
	char ch;
	SqList<char> L, M, U;
	List_Sq<char> list_sq, list_merge, list_union;
	
	list_sq.InitList_Sq(L);				// 初始化線性表
	
	list_sq.ListInsert_Sq(L, 1, 'a');	// 插入五個字元並輸出
	list_sq.ListInsert_Sq(L, 2, 'b');
	list_sq.ListInsert_Sq(L, 3, 'c');
	list_sq.ListInsert_Sq(L, 4, 'd');
	list_sq.ListInsert_Sq(L, 5, 'd');
	list_sq.ListInsert_Sq(L, 6, 'e');
	cout << "線性表中的初始元素為:";
	list_sq.output(L);

	if (!list_sq.ListEmpty_Sq(L))
	{
		cout << "線性表長:" << list_sq.ListLength_Sq(L) << endl;
	}

	list_sq.GetElem_Sq(L, 3, ch);
	cout << "第3個元素為:" << ch << endl;	
	
	cout << "線性表中第一個與‘d’相等的元素的位序:" << list_sq.LocateElem_Sq(L, 'd', compare<char>) << endl;
	
	list_sq.PriorElem_Sq(L, 'b', ch);
	cout << "資料元素‘b’的前驅:" << ch << endl;
	list_sq.NextElem_Sq(L, 'b', ch);
	cout << "資料元素‘b’的後繼:" << ch << endl;
	list_sq.ListDelete_Sq(L, 6, ch);
	
	cout << "刪除第6個元素,該元素為:" << ch << endl;
	cout << "刪除元素後的線性表為:";
	list_sq.output(L);

	list_merge.InitList_Sq(M);
	list_merge.ListInsert_Sq(M, 1, 'a');
	list_merge.ListInsert_Sq(M, 2, 'b');
	list_merge.ListInsert_Sq(M, 3, 'f');
	cout << "新建一個線性表:";
	list_merge.output(M);
	
	MergeList_Sq(L, M, U);
	cout << "兩個順序線性表按值非遞減排列合併後為:";
	list_union.output(U);
	
	list_union.ClearList_Sq(U);
	cout << "將合併後的順序線性表置空後為:";
	list_union.output(U);
	
	cout << "銷燬3個線性表,程式結束。" << endl;
	list_sq.DestroyList_Sq(L);
	list_merge.DestroyList_Sq(M);
	list_union.DestroyList_Sq(U);

	return 0;
}

      測試效果截圖:


    因個人水平有限,如有錯誤,還請各位批評指正。