內部排序算法
時間複雜度: O(n^2) O(n^2) O(n^2)
空間複雜度: O(1) O(1) O(1)
算法名稱: 插入 選擇 冒泡
算法名稱: 希爾 堆 快速 歸併 基數
空間複雜度:O(1) O(1) O(logn) O(n) O(2rd)
時間複雜度:O(nlogn) O(nlogn) O(nlogn) O(nlogn) O(d(n+rd))
穩定的:插入 冒泡 歸併 基數
其它:不穩定排序。
示列代碼:
#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAXSIZE 500
typedef int KeyType;////定義關鍵字類型
typedef char InfoType;
struct RecType
{
KeyType key;//關鍵字項
InfoType data;//其他數據項,類型爲InfoType
}R[MAXSIZE],R1[MAXSIZE];
//插入排序
void StrInsSort(RecType R[],int n)//直接插入排序
{
//時間複雜度O(n2)
for(int i=2;i<=n;i++)
{
R[0]=R[i];//將待排序記錄放進監視哨
int j=i-1;
while(R[0].key<R[j].key)
{
R[j+1]=R[j];//記錄後移
j--;
}
R[j+1]=R[0];//將待排序記錄放到合適位置
}
}
void BinsSort(RecType R[],int n)//折半插入排序
{
//折半插入排序僅僅是減少了關鍵字間的比較次數,
//但是記錄移動的次數不變,所以時間複雜度仍然爲:O(n2)
for(int i=2;i<=n;i++)
{
R[0]=R[i];
int low=1,high=i-1;//設置折半查找的範圍
while(low<=high)//折半查找插入位置
{
int m=(low+high)/2;
if(R[0].key<R[m].key)high=m-1;
else low=m+1;
}
for(int j=i-1;j>=high+1;j--)
R[j+1] = R[j];//記錄後移
R[high+1] = R[0];//插入
}
}
void ShellSort(RecType R[],int n)//希爾排序
{
//時間複雜度爲:O(n1.3)
//Shell:d1= n/2 , di+1= di/2 ,最後一個取1
for(int d=n/2;d>=1;d=d/2)
{
for(int i=1+d;i<=n;i++)
{
//將R[i]插入到所屬組的有序列段中,直接插入排序
R[0]=R[i];
int j=i-d;
while(j>0&&R[0].key<R[j].key)
{
R[j+d]=R[j];//記錄後移,查找插入位置
j=j-d;
}
R[j+d]=R[0];//將第i個元素插入到合適位置
}
}
}
//交換排序
void BubbleSort(RecType R[],int n)//起泡排序
{
//時間複雜度O(n2)
for(int i=1;i<n;i++)//最多n-1趟起泡
{
for(int j=1;j<=n-i;j++)//每趟都把最大的放在最後面
{
//兩兩比較,發現逆序立即交換
if(R[j].key>R[j+1].key)
{
RecType temp = R[j];
R[j]=R[j+1];
R[j+1]=temp;
}
}
}
}
void BubbleSort1(RecType R[],int n)//改進的起泡排序
{
//時間複雜度O(n2)
int i =n;//i指示無序序列中最後一個記錄的位置
while(i>1)//冒泡排序的結束條件爲:最後一趟沒有進行交換
{
int lastExchange = 1;//記錄最後一次交換髮生的位置
for(int j=1;j<i;j++)
{
if(R[j].key>R[j+1].key)
{
RecType temp = R[j];
R[j]=R[j+1];
R[j+1]=temp;
lastExchange=j;
}
}
i = lastExchange;
}
}
//快速排序也叫分區交換排序
int Partition(RecType R[],int low,int high)
{
//交換記錄子序列R[low..high]中的記錄,使樞軸記錄
//到位並返回其 所在位置,此時,在它之前(後)的記錄均不大(小)於它
R[0] = R[low];//以子表的第一個記錄作樞軸,將其暫存到記錄R[0]中
int pivotkey = R[low].key;//樞軸記錄關鍵字
while(low<high)
{
//從表的兩端交替地向中間掃描
while(low<high && R[high].key>=pivotkey)high--;
R[low] = R[high];//將比樞軸小的記錄移到低端
while(low<high && R[low].key<=pivotkey)low++;
R[high]=R[low];//將比樞軸大的記錄移到高端
}
R[low]=R[0];//樞軸記錄到位
return low;//返回樞軸位置
}
void change(RecType R[],int low,int high)//快速排序前進行預處理
{
//比較R[s].key和R[t].key和R[(s+t)/2].key,
//然後取關鍵字爲“三者之中值”的記錄作爲樞軸記錄,將其與R[s]互換即可
if(R[low].key>=R[high].key)
{
if(R[low].key>=R[(low+high)/2].key)
{
if(R[(low+high)/2].key>=R[high].key)
{
RecType temp = R[(low+high)/2];
R[(low+high)/2] = R[low];
R[low] = temp;
}
else
{
RecType temp = R[high];
R[high] = R[low];
R[low] = temp;
}
}
}
else
{
if(R[high].key>=R[(low+high)/2].key)
{
if(R[(low+high)/2].key>=R[low].key)
{
RecType temp = R[(low+high)/2];
R[(low+high)/2] = R[low];
R[low] = temp;
}
}
}
}
void QSort(RecType R[],int low,int high)
{
//對記錄序列R[low..high]進行快速排序
if(low<high)//長度大於1
{
change(R,low,high); //爲了避免出現一趟排序後記錄集中在樞軸一側的情況,快速排序前進行預處理
int location = Partition(R,low,high);//獲得樞軸位置,將R[low..high]分成兩部分
QSort(R,low,location-1);
QSort(R,location+1,high);
}
}
void QuickSort(RecType R[],int n)
{
//時間複雜度nlogn
//對記錄序列進行快速排序
QSort(R,1,n);
}
//選擇排序
void SelectSort(RecType R[],int n)//直接選擇排序
{
//時間複雜度O(n2)
for(int i=1;i<n;i++)
{
//選擇第i小的記錄,並交換到位
int k=i;//假定第i個元素的關鍵字最小
for(int j=i+1;j<=n;j++)//找最小元素的下標
{
if(R[j].key<R[k].key)k=j;
}
if(i!=k)
{
RecType temp = R[i];
R[i]=R[k];
R[k]=temp;
}
}
}
void Sift(RecType R[],int i,int m)//調整堆的算法,篩選
{
//假設R[i+1..m]中各元素滿足堆的定義,
//本算法調整R[i]使序列R[i..m]中各元素滿足堆的性質
R[0]=R[i];//暫存“根”記錄R[i]
for(int j=2*i;j<=m;j*=2)//j<=m時,R[2i]是R[i]的左孩子
{
//若R[i]的右孩子存在,且關鍵字大於左孩子,j指向R[i]的右孩子
//j指向關鍵字最大的孩子
if(j<m&&R[j].key<R[j+1].key)j++;
if(R[0].key<R[j].key)//孩子結點關鍵字較大
{
R[i]=R[j];//將R[j]換到雙親位置
i=j;
}
else break;//調整完畢,退出循環
}
R[i]=R[0];//最初被調整結點放入正確位置
}
void HeapSort(RecType R[],int n)//堆排序
{
//時間複雜度O(nlogn),待排序數目小的話不提倡用堆排序,因爲建堆太費時
//對記錄序列R[1..n]進行堆排序。
for(int i=n/2;i>0;i--)//把R[1..n]建成大頂堆,對於完全二叉樹,n/2正好是最後一個非葉子結點
{
Sift(R,i,n);
}
for(int j=n;j>1;j--)
{
//將堆頂記錄和當前未經排序子序列R[1..i]中
//最後一個記錄相互交換
RecType temp=R[1];
R[1]=R[j];
R[j]=temp;
Sift(R,1,j-1);//將R[1..i-1]重新調整爲大頂堆
}
}
//歸併排序
void Merge(RecType R[],RecType R1[],int i,int l,int h)
{
//將有序的R[i..l]和R[l+1..h]歸併爲有序的R1[i..h]
int j,k;
for(j=l+1,k=i;i<=l&&j<=h;k++)
{
//將R中記錄由小到大地併入R1
if(R[i].key<=R[j].key)R1[k]=R[i++];
else R1[k]=R[j++];
}
if(i<=l)//將剩餘的R[i..l]複製到R1
{
for(;i<=l;i++)
{
R1[k++]=R[i];
}
}
if(j<=h)//將剩餘的R[j..h]複製到R1
{
for(;j<=h;j++)
{
R1[k++]=R[j];
}
}
}
void Msort(RecType R[],RecType R1[],int s,int t)
{
//將R[s..t]進行2-路歸併排序爲R1[s..t]
RecType R2[MAXSIZE];
if(s==t)R1[s]=R[s];//長度爲1
else
{
int m=(s+t)/2;//將R[s..t]平分爲R[s..m]和R[m+1..t]
Msort(R,R2,s,m);//遞歸地將R[s..m]歸併爲有序的R2[s..m]
Msort(R,R2,m+1,t);//遞歸地將R[m+1..t]歸併爲有序的R2[m+1..t]
Merge(R2,R1,s,m,t);//將R2[s..m]和R2[m+1..t]歸併到R1[s..t]
}
}
void MergeSort(RecType R[],int n)//2-路歸併排序
{
//時間複雜度O(nlogn)
//對記錄序列R[1..n]作2-路歸併排序。
//RecType R1[MAXSIZE];
Msort(R,R1,1,n);
}
void select()
{
cout<<"歡迎進入排序操作界面"<<endl;
cout<<"1,初始化待排序的序列"<<endl;
cout<<"2,直接插入排序"<<endl;
cout<<"3,折半插入排序"<<endl;
cout<<"4,希爾排序"<<endl;
cout<<"5,起泡排序"<<endl;
cout<<"6,改進的起泡排序"<<endl;
cout<<"7,快速排序"<<endl;
cout<<"8,直接選擇排序"<<endl;
cout<<"9,堆排序"<<endl;
cout<<"10,二路歸併排序"<<endl;
cout<<"11,輸出序列"<<endl;
cout<<"0,退出"<<endl;
}
int main()
{
int n,i=0,flg=0,op;
select();
while(1)
{
cout<<"輸入操作序號"<<endl;
cin>>op;
switch(op)
{
case 0:exit(0);break;
case 1:
cout<<"輸入待排序的數字的個數:"<<endl;
cin>>n;
cout<<"依此輸入數字"<<endl;
for(i=1;i<=n;i++)
{
cin>>R[i].key;
}
cout<<"序列初始化完成"<<endl;break;
case 2:StrInsSort(R,n);cout<<"直接插入排序完成"<<endl;break;
case 3:BinsSort(R,n);cout<<"折半插入排序完成"<<endl;break;
case 4:ShellSort(R,n);cout<<"希爾排序完成"<<endl;break;
case 5:BubbleSort(R,n);cout<<"起泡排序完成"<<endl;break;
case 6:BubbleSort1(R,n);cout<<"改進後的起泡排序完成"<<endl;break;
case 7:QuickSort(R,n);cout<<"快速排序完成"<<endl;break;
case 8:SelectSort(R,n);cout<<"直接選擇排序完成"<<endl;break;
case 9:HeapSort(R,n);cout<<"堆排序完成"<<endl;break;
case 10:MergeSort(R,n);cout<<"二路歸併排序完成"<<endl;flg=1;break;
case 11:cout<<"序列爲"<<endl;
if(flg==0)
{
for(int j=1;j<=n;j++)
{
cout<<R[j].key<<" ";
}
}
else
{
for(int j=1;j<=n;j++)
{
cout<<R1[j].key<<" ";
}
flg=0;
}
cout<<endl;break;
default:cout<<"輸入操作錯誤"<<endl;break;
}
}
}