順序儲存線性表的C++實現——嚴蔚敏版《資料結構》
阿新 • • 發佈:2019-02-01
因為最近在拿嚴蔚敏版的《資料結構》複習相關知識,所以就通過動手實現來加深理解,在這裡與大家分享。話不多說,直接上程式碼,註釋比較詳細,就不另外解說了。
首先是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; }
測試效果截圖:
因個人水平有限,如有錯誤,還請各位批評指正。