線性錶鏈式儲存(靜態連結串列)及其12種操作的實現
阿新 • • 發佈:2019-01-29
該表格中的所有複雜度均指的是當前程式中演算法的複雜度,同一個操作演算法不同複雜度不同。
對於空間複雜度:沒有程式的空間複雜度為0,任何程式的執行必須要空間。當所需的空間是常數的,就是O(1);是線性的,就是O(n),以此類推。
操作 |
時間複雜度(T(n)) |
空間複雜度(S(n)) |
判斷是否為空 |
O(1) |
O(1) |
得到長度 |
O(n) |
O(1) |
轉置線性表 |
O(n) |
O(1) |
得到指定下標的元素 |
O(n) |
O(1) |
得到指定元素的下標 |
O(n) |
O(1) |
插入元素 |
O(n) |
O(1) |
刪除元素 |
O(n) |
O(1) |
氣泡排序 |
O(n^2) |
O(1) |
清空當前線性表 |
O(n) |
O(1) 因為整個一維陣列的空間早已經宣告,只是使用和不使用之分,無開闢新記憶體和回收記憶體 |
歸併兩個已經有序的線性表(長度分別n,m)的交集到第一個線性表,且保持新表有序 |
O(n+m) 最壞的情況下 |
O(1) 事實上是多使用了O(m)的記憶體,因為要將s2的所有元素複製到s1中 |
/* 資料結構分析與學習專欄 * Copyright (c) 2015, 山東大學電腦科學與技術專業學生 * All rights reserved. * 作 者: 高祥 * 完成日期: 2015 年 3 月 25 日 * 版 本 號:003 *任務描述:針對線性表的採用順序儲存結構,實現15個基本操作 * 1:建立靜態連結串列,填充元素 * 2:輸出靜態連結串列 * 3:判斷靜態連結串列是否為空 * 4:求靜態連結串列的長度 * 5:反轉靜態連結串列 * 6:查詢靜態連結串列指定下標的元素 * 7:求出給定元素在靜態連結串列中第一次出現的位置 * 8:向靜態連結串列中的指定位置插入元素 * 9:刪除靜態連結串列中指定位置的元素 * 10:清空當前靜態連結串列 * 11:將靜態連結串列按照升序排序 * 12:將兩個靜態連結串列歸併到第一個靜態連結串列中並按照升序排列 *主要函式: * 1.void InitList(SLinkList &s); //初始化靜態連結串列:將一維陣列的各分量鏈成一個備用連結串列,s[0].cur為第一個結點 //0表示空指標 * 2.int Malloc(SLinkList &s);//若備用連結串列空間非空,則返回分配的結點下標,否則返回0 * 3.void Free(SLinkList &s,int index);//將下標為k的空閒節點回收到備用連結串列中 * 4.void FillList(SLinkList &s,int &head); //填充靜態連結串列的元素,注意:head要使用引用傳值 * 5.void Output(SLinkList s,int head);//輸出靜態連結串列 * 6.Status IsEmpty(SLinkList s,int head);//判斷靜態連結串列是否為空 * 7.int ListLength(SLinkList s,int head);//求靜態連結串列的長度 * 8.void ReverseList(SLinkList &s,int head);//反轉靜態連結串列 * 9.void GetElem(SLinkList s,int index,int head);//得到指定下標的元素 * 10.void GetIndex(SLinkList s,ElemType elem,int head);//得到指定元素的下標 * 11.void InsertList(SLinkList &s,int head,int index,ElemType elem);//插入元素 * 12.void DeleteList(SLinkList &s,int head,int index);//刪除結點 * 13.Status ClearList(SLinkList &s,int head);//清空靜態連結串列 * 14.void BubbleSort(SLinkList &s,int head);//氣泡排序 * 15.void MergeList(SLinkList &s1,int head1,SLinkList &s2,inthead2); //歸併兩個靜態連結串列到第一個靜態連結串列中並保持升序 */ #include<iostream> #include<algorithm> using namespace std; #define OK 1 #define FALSE 0 #define ERROR 0 #define MAXSIZE 100000 typedef int ElemType; typedef int Status; typedef struct { ElemType data; int cur; } component,SLinkList[MAXSIZE]; void Interaction(); void InitList(SLinkList &s); //初始化靜態連結串列:將一維陣列的各分量鏈成一個備用連結串列,s[0].cur為第一個結點,0表示空指標 int Malloc(SLinkList &s);//若備用連結串列空間非空,則返回分配的結點下標,否則返回0 void Free(SLinkList &s,int index);//將下標為k的空閒節點回收到備用連結串列中 void FillList(SLinkList &s,int&head);//填充靜態連結串列的元素,注意:head要使用引用傳值 void Output(SLinkList s,int head);//輸出靜態連結串列 Status IsEmpty(SLinkList s,int head);//判斷靜態連結串列是否為空 int ListLength(SLinkList s,int head);//求靜態連結串列的長度 void ReverseList(SLinkList &s,inthead);//反轉靜態連結串列 void GetElem(SLinkList s,int index,inthead);//得到指定下標的元素 void GetIndex(SLinkList s,ElemType elem,inthead);//得到指定元素的下標 void InsertList(SLinkList &s,inthead,int index,ElemType elem);//插入元素 void DeleteList(SLinkList &s,inthead,int index);//刪除結點 Status ClearList(SLinkList &s,inthead);//清空靜態連結串列 void BubbleSort(SLinkList &s,inthead);//氣泡排序 void MergeList(SLinkList &s1,inthead1,SLinkList &s2,int head2); //歸併兩個靜態連結串列到第一個靜態連結串列中並保持升序 int main() { SLinkList s1,s2; Interaction(); int operate; int head1,head2; while(cin>>operate) { switch(operate) { case 0: return 0; case 1: InitList(s1); FillList(s1,head1); break; case 2: Output(s1,head1); break; case 3: if(IsEmpty(s1,head1)) { cout<<"靜態連結串列為空。\n"; } else { cout<<"靜態連結串列不為空。\n"; } break; case 4: cout<<"靜態連結串列的長度是:"<<ListLength(s1,head1)<<endl; break; case 5: ReverseList(s1,head1); break; case 6: cout<<"請輸入下標:"; int index; cin>>index; GetElem(s1,index,head1); break; case 7: cout<<"請輸入元素大小:"; ElemType elem; cin>>elem; GetIndex(s1,elem,head1); break; case 8: cout<<"請輸入要插入的元素大小及其位置:"; cin>>elem>>index; InsertList(s1,head1,index,elem); break; case 9: cout<<"請輸入要刪除的元素的下標:"; cin>>index; DeleteList(s1,head1,index); break; case 10: if(ClearList(s1,head1)) { cout<<"清空靜態連結串列成功。\n"; } break; case 11: BubbleSort(s1,head1); break; case 12: InitList(s2); FillList(s2,head2); MergeList(s1,head1,s2,head2); break; default: cout<<"請輸入正確的運算元字!\n"; break; } } return 0; } void Interaction() { cout<<"請輸入對應操作的序號:\n"; cout<<"0:退出程式;\n"; cout<<"1:建立靜態連結串列,填充元素;\n"; cout<<"2:輸出靜態連結串列;\n"; cout<<"3:判斷靜態連結串列是否為空;\n"; cout<<"4:求靜態連結串列的長度 ;\n"; cout<<"5:反轉靜態連結串列;\n"; cout<<"6:查詢靜態連結串列指定下標的元素;\n"; cout<<"7:求出給定元素在靜態連結串列中第一次出現的位置;\n"; cout<<"8:向靜態連結串列中的指定位置插入元素;\n"; cout<<"9:刪除靜態連結串列中指定位置的元素;\n"; cout<<"10:清空當前靜態連結串列;\n"; cout<<"11:將靜態連結串列按照升序排序;\n"; cout<<"12:將兩個靜態連結串列歸併到第一個靜態連結串列中並按照升序排列;\n"; } void InitList(SLinkList &s) //初始化靜態連結串列:將一維陣列的各分量鏈成一個備用連結串列,s[0].cur為第一個結點,0表示空指標 { for(int i=0; i<MAXSIZE-1; i++) { s[i].cur=i+1; } s[MAXSIZE-1].cur=0; } int Malloc(SLinkList &s)//若備用連結串列空間非空,則返回分配的結點下標,否則返回0 { int i=s[0].cur; if(i) { s[0].cur=s[i].cur;//取出一個備用結點,更新下一個可用結點的下標 } return i; } void Free(SLinkList &s,int index)//將下標為k的空閒節點回收到備用連結串列中 { s[index].cur=s[0].cur; s[0].cur=index; } void FillList(SLinkList &s,int&head)//填充靜態連結串列的元素,注意:head要使用引用傳值 { cout<<"請輸入元素的個數:"; int listsize; cin>>listsize; head=Malloc(s);//生成頭結點 int r=head;//r是尾結點 cout<<"請輸入元素:"; for(int i=1; i<=listsize; i++) { int index=Malloc(s); if(index) { cin>>s[index].data; s[r].cur=index; r=index;//更新尾結點的索引 } } s[r].cur=0;//最後指向空指標 cout<<"靜態連結串列是:"; Output(s,head); } void Output(SLinkList s,int head)//輸出靜態連結串列 { if(!IsEmpty(s,head)) { int index=s[head].cur;//第一個結點 while(index) { cout<<s[index].data<<" "; index=s[index].cur;//更新結點 } cout<<endl; } else { cout<<"靜態連結串列為空,無法輸出。\n"; } } Status IsEmpty(SLinkList s,int head)//判斷靜態連結串列是否為空 { if(s[head].cur==0) { return OK; } return FALSE; } int ListLength(SLinkList s,int head)//求靜態連結串列的長度 { int length=0; int index=s[head].cur; while(index) { length++; index=s[index].cur; } return length; } void ReverseList(SLinkList &s,inthead)//反轉靜態連結串列 { int p,q; p=s[head].cur; q=s[p].cur; s[p].cur=0; while(q) { int index=s[q].cur;//預存下一個結點 s[q].cur=p; p=q;//更新結點 q=index; } s[head].cur=p;//最後轉換頭結點 cout<<"反轉後的靜態連結串列是:"; Output(s,head); } void GetElem(SLinkList s,int index,inthead)//得到指定下標的元素 { if(index<1||index>ListLength(s,head)) { cout<<"位置越界,無法輸出。\n"; return; } int num=1; int index2=s[head].cur; while(1) { if(num==index) { cout<<"第"<<index<<"個元素是:"<<s[index2].data<<endl; return; } num++; index2=s[index2].cur; } } void GetIndex(SLinkList s,ElemType elem,inthead)//得到指定元素的下標 { int num=1; int index=s[head].cur; while(index) { if(s[index].data==elem) { cout<<"元素"<<elem<<"是靜態連結串列中的第"<<num<<"個元素。\n"; return; } num++; index=s[index].cur; } cout<<"未找到,已退出。\n"; } void InsertList(SLinkList &s,inthead,int index,ElemType elem)//插入元素 { if(index<1||index>ListLength(s,head)) { cout<<"位置越界,無法插入。\n"; return; } int num=0; int p=head; while(num<=index-2) { num++; p=s[p].cur; } int newnode=Malloc(s); s[newnode].data=elem; s[newnode].cur=s[p].cur; s[p].cur=newnode; cout<<"靜態連結串列是:"; Output(s,head); } void DeleteList(SLinkList &s,inthead,int index)//刪除結點 { if(index<1||index>ListLength(s,head)) { cout<<"位置越界,無法刪除。\n"; return; } int num=0; int p=head; while(num<=index-2) { num++; p=s[p].cur; } int deletenode=s[p].cur; s[p].cur=s[deletenode].cur; Free(s,deletenode);//回收被刪除的結點 cout<<"靜態連結串列是:"; Output(s,head); } Status ClearList(SLinkList &s,inthead)//清空靜態連結串列 { int index=s[head].cur; while(index) { int index2=s[index].cur; Free(s,index);//回收結點 index=index2; } return OK; } void BubbleSort(SLinkList &s,inthead)//氣泡排序 { int i=s[head].cur,j; while(i) { j=s[i].cur; while(j) { if(s[i].data>s[j].data) { swap(s[i].data,s[j].data); } j=s[j].cur; } i=s[i].cur; } cout<<"排序後的靜態連結串列是:"; Output(s,head); } void MergeList(SLinkList &s1,inthead1,SLinkList &s2,int head2) //歸併兩個靜態連結串列到第一個靜態連結串列中並保持升序 { if(!IsEmpty(s1,head1)&&!IsEmpty(s2,head2)) { BubbleSort(s1,head1);//先對兩個分靜態連結串列排序 BubbleSort(s2,head2); int p=s1[head1].cur,q=s2[head2].cur; int index=head1; while(p&&q)//當沒有連結串列歸併完時 { if(s1[p].data<=s2[q].data) { s1[index].cur=p; //因為歸併到第一個連結串列中,所以s1[p].data<=s2[q].data時,只需要改變連結串列s1的結點指向即可,無需宣告新結點 index=p;//更新“新”靜態連結串列的結點指標 p=s1[p].cur;//更新未歸併的結點的指標 } else { int newnode=Malloc(s1);//宣告新節點,複製到靜態連結串列s1中 s1[newnode].data=s2[q].data; s1[index].cur=newnode;//完成指標轉移 index=newnode; q=s2[q].cur; } } while(q)//當s1本身完成歸併但是s2未完成歸併時,將剩餘的所有s2的結點全部複製到s1連結串列中 { int newnode=Malloc(s1); s1[newnode].data=s2[q].data; s1[index].cur=newnode; index=newnode; q=s2[q].cur; } s1[index].cur=0;//終結新連結串列 if(p)//當s2完成歸併但是s1未完成歸併時,只需要將“新”s1最後一個元素的指標連線到將要被歸併的第一個元素上 { s1[index].cur=p; } cout<<"歸併後的靜態連結串列是:"; Output(s1,head1); ClearList(s2,head2); return; } cout<<"靜態連結串列為空,無法歸併。\n"; }