1. 程式人生 > >線性錶鏈式儲存(靜態連結串列)及其12種操作的實現

線性錶鏈式儲存(靜態連結串列)及其12種操作的實現

該表格中的所有複雜度均指的是當前程式中演算法的複雜度,同一個操作演算法不同複雜度不同。

對於空間複雜度:沒有程式的空間複雜度為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";
}