1.線性表建立、元素插入、元素刪除、線性表合併(原創)
阿新 • • 發佈:2019-01-24
參考書籍:資料結構(C語言版)--嚴蔚敏(清華大學出版社)
最近在學資料結構,選用以上參考資料,書中的例子只是一個程式設計參考,並不能直接使用,這裡我給出完整例項(程式設計
思想與書本保持一致)。
實際問題1:假設利用兩個線性表LA和LB分別表示兩個集合A和B(即線性表中的資料元素即為集合中的成員),現要求
一個新的集合A=A U B(並運算)。這就要求:擴大線性表LA,將存在於線性表LB中而不存在與線性表LA中的資料元素
插入到線性表LA中去。--只要從線性表LB中依次取得每個資料元素,並依值線上性表LA中進行查訪,若不存在則插入之。
實際問題2:已知線性表LA和LB的資料元素按值非遞減有序排列,現在要求將LA和LB併為一個新的線性表LC,且LC中的
資料元素仍按值非遞減有序排列。
實際問題1用演算法函式1解決,實際問題2用演算法函式2解決,因為兩個問題用到的函式很多是一樣的,所以寫在一個程式檔案中。
其中:需要注意易錯點:
(1)插入操作函式輸入的插入位置是位序,不是陣列下標,並且是插入到位序之前,如果要在位序之後,必須再加1(記得輸入合法性判斷)
(2)插入操作函式不可以對空表進行操作,因為L.length不能為0,至少為1,也就是需要一個函式來初始化線性表第一個元素
(3)元素定位函式必須對端點值進行單獨判斷
(4)插入操作函式和刪除操作函式都是複雜度比較高的操作,因為涉及後續所有元素的向前/向後移位,效率比較低
(5)對於線性表(如陣列)的指標操作更快捷,但是記得次數判斷時多使用末尾元素指標作為迴圈終止條件
(6)合併已排序線性表函式ListMergeOrder_better使用指標操作,用複製代替ListMergeOrder函式的插入操作(需要遍歷),效率更高
#include<iostream> using namespace std; #define Size_InitList 100 #define Increment_List 10 int la[Size_InitList] = { 1, 2, 6, 7 }; int lb[Size_InitList] = { 4, 5, 6, 7, 8, 9, 10, 11 }; typedef struct{ int* elem; int length; int listsize; }Sqlist; void ListInit(Sqlist &L); int ListFirstDataInit(Sqlist &L, int ListFirstData); int ExistenceElem(Sqlist L, int e); int ListInsert(Sqlist &L, int i, int insertdata); int ListDelete(Sqlist &L, int i, int &deletedata); void ListDisplay(Sqlist L); void UnionList(Sqlist &La, Sqlist Lb); void ListMergeOrder(Sqlist &Lc, Sqlist La, Sqlist Lb); void ListMergeOrder_better(Sqlist &Lc, Sqlist La, Sqlist Lb); int main(){ Sqlist La, Lb, Lc; ListInit(La); ListInit(Lb); ListInit(Lc); for (int i = 0; i < 4; i++){ if (i == 0){ ListFirstDataInit(La,la[i]); } ListInsert(La, i + 1, la[i]);//插到第i個元素之後,為i+1 } for (int i = 0; i < 8; i++){ if (i == 0){ ListFirstDataInit(Lb, lb[i]); } ListInsert(Lb, i + 1, lb[i]); } /*******解題演算法1:合併線性表La和Lb(相同元素不重複)*********/ //UnionList(La,Lb); //ListDisplay(La); /*******解題演算法2:合併線性表La和Lb(相同元素重複),並且重新排序********/ ListMergeOrder_better(Lc, La, Lb); ListDisplay(Lc); return 0; } void ListInit(Sqlist &L){ L.elem = (int*)malloc(Size_InitList*sizeof(int)); if (!L.elem){ cout << "Memory allocation fail!" << endl; exit(1); } L.length = 0; L.listsize = Size_InitList; } int ListFirstDataInit(Sqlist &L, int ListFirstData){ L.elem[0] = ListFirstData; return 0; } /************************************ ListInsert *********************************** //線性表元素插入 //第一:線性表不能為空(無法初始化第一個元素,因為L.length不能為0); //第二:這裡的i是位序,如果插到第i元素前則為i,如果插到第i元素後則為i+1 //第三:時間複雜度:O(L.length) */ int ListInsert(Sqlist &L, int i, int insertdata){ if (i<1 || i>L.length + 1){//L.length+1:可以插入到最後一個元素的後面 cout << "InserList input error!" << endl; return 0; } if (L.length >= L.listsize){ int* newbase = (int*)realloc(L.elem, (L.listsize + Increment_List)*sizeof(int)); if (!newbase){//分配失敗 exit(1); } L.elem = newbase; L.listsize += Increment_List; } int* remark = &L.elem[i - 1];//注意:remark所指的元素是開始往後移動的元素,所以p>=remark取到等號 int* p = &L.elem[L.length - 1]; for (; p >= remark; p--){ *(p + 1) = *p; } *remark = insertdata; ++L.length; return 0; } /******************************** ListDelete ****************************************** //線性表元素刪除 //時間複雜度:O(L.length) */ int ListDelete(Sqlist &L, int i, int &deletedata){ if (i<1 || i>L.length){ cout << "ListDelete:ListDelete Input error!" << endl; return 0; } int* last = &L.elem[L.length - 1]; int* p = &L.elem[i - 1]; deletedata = *p; for (; p < last; p++){ *p = *(p + 1); } --L.length; return 0; } void ListDisplay(Sqlist L){ for (int i = 0; i < L.length; i++){ cout << L.elem[i] << ' '; } cout << endl; } /******************************* ExistenceElem ******************************************* //判斷線性表中元素的存在性 //查詢L中是否存在元素e,不存在返回0,否則返回非0值(返回位序); //時間複雜度:O(L.length) */ int ExistenceElem(Sqlist L, int e){ for (int i = 0; i < L.length; i++){ if (L.elem[i] == e){ return i + 1; } } return 0; } int ElemLocate(Sqlist L, int elem){//e為要查詢的元素,函式返回實際要插入的位序 if (elem <= L.elem[0]){//端點值單獨判斷 return 1; } if (elem >= L.elem[L.length - 1]){//端點值單獨判斷 return L.length + 1; } for (int i = 0; i < L.length - 1; i++){ if (elem > L.elem[i] && elem <= L.elem[i + 1]){ return i + 2; } else continue; } return 0; } /************************************* UnionList *********************************** //演算法函式1:合併線性表La和Lb(相同元素不重複) //將Lb中與La不同的元素插入到La中去 //時間複雜度:O(La.length * Lb.length), ExistenceElem執行時間和表長成正比,ListInsert和表長無關 */ void UnionList(Sqlist &La, Sqlist Lb){ for (int i = 0; i < 8; i++){ if (!ExistenceElem(La, Lb.elem[i])){//只需在最開始的La裡面查詢(Lb中資料插入La中為“追加”),不會影響Lb中重複的元素 ListInsert(La, La.length + 1, Lb.elem[i]);//將Lb中元素追加到La後面,每次La.length都會更新 } } } /************************************ ListMergeOrder ********************************* //演算法函式2:合併線性表La和Lb(相同元素重複),並且重新排序 //注意:Lc可以為空,無需初始化第一個元素 //時間複雜度:O(La.length + Lb.length) */ void ListMergeOrder(Sqlist &Lc, Sqlist La, Sqlist Lb){ int remark; for (int i = 0; i < La.length; i++){ Lc.elem[i] = La.elem[i]; ++Lc.length; } for (int i = 0; i < Lb.length; i++){ remark = ElemLocate(Lc, Lb.elem[i]); ListInsert(Lc, remark, Lb.elem[i]); } } /***************************** ListMergeOrder_better ******************************************* //演算法函式2(效率更高):合併線性表La和Lb(相同元素重複),並且重新排序 //注意要對Lc分配空間,否則不能保證資料是否放得下 //因為這裡是對有序線性表合併,所以要比之前的 ListUnion 時間複雜度更低
//時間複雜度:O(La.length + Lb.length)
*/
void ListMergeOrder_better(Sqlist &Lc, Sqlist La, Sqlist Lb){
int i=0,j=0, Len_a, Len_b;
int* pa = La.elem;
int* pb = Lb.elem;
int* pa_last = La.elem + La.length - 1;
int* pb_last = Lb.elem + Lb.length - 1;
Lc.length = La.length + Lb.length;
int* pc =Lc.elem= (int*)malloc(Lc.length*sizeof(int));//保證Lc空間足夠
if (!pc){
cout << "ListMergeOrder_better:Memory allocation fail!" << endl;
exit(1);
}
while (pa <= pa_last&&pb <= pb_last){//使用末尾元素指標作為次數判斷更加方便
if (*pa <= *pb){//如果將*pa==*pb分開,並且兩個元素中只插入一個,就變成了ListUnion函數了
//只是這裡時間複雜度更低,因為使用複製代替了元素查詢
*pc++ = *pa++;
}
else{
*pc++ = *pb++;
}
}
while (pa <= pa_last){
*pc++ = *pa++;
}
while (pb <= pb_last){
*pc++ = *pb++;
}
}