前段時間,由於有些事情的耽誤,還有就是自己有點懶,所以很久沒有寫博客了,今天打算給大家帶來數據結構中的常見問題——排序,同時這也是面試中經常被問到的部分,因此今天決定對各種排序算法進行自我梳理一遍,以此鞏固自己的基礎。
排序算法常見的有:冒泡排序,選擇排序,直接插入排序,希爾排序,歸併排序,快速排序,堆排序,基數排序這八種排序算法,主要從時間複雜度、空間複雜度、穩定性、是否與初始的次序有關等方面來評價該排序算法的優劣。
以上四點判斷,其實只要真正明白了其算法思想,按照其流程走,不難分析出其中的緣由。網上分析其思想原理的資料太多,我在此就不在贅述了。直接給出C++代碼實現,以供大家參考,大家有什麼建議和意見,可以直接留言或私信。
"sort_algorithms.h":
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
//冒泡排序
void bubble_sort(int *, int n );
//選擇排序
void choose_sort(int *, int n);
//插入排序
void insert_sort(int *, int n);
//希爾排序
void shell_sort(int *, int n);
//歸併排序
void merge_sort(int *, int begin, int end, int *);
void merge_array(int *,int begin, int mid, int end, int *);
void MergeSort(int *, int n);
//快速排序
void quick_sort(int *, int begin, int end);
void QuickSort(int *, int n);
//顯示輸出數組
void display(int *arr, int n);
//隨機產生1-n的整數
long random(long n);
#include"sort_algorithms.h"
//冒泡排序
void bubble_sort(int *arr, int n)
{
if( NULL == arr ||n < 1)
return;
int temp;
//因爲冒泡排序的效率和數組初始化的次序有關,用來判斷後面的是否已經排好序,以便直接退出,提供效率
bool isOver = true;
for(int i = 0; i < n - 1; ++i)
{
isOver = true;
for(int j = 0; j < n - 1 - i; ++j)
{
if(arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isOver = false;
}
}
if(isOver)
break;
}
display(arr, n);
}
//選擇排序
void choose_sort(int * arr, int n)
{
if( NULL == arr ||n < 1)
return;
int max, index, temp;
for(int i = 0; i < n; ++i)
{
max = arr[0];
index = 0;
for(int j = 0; j < n - i; ++j)
{
if(arr[j] > max)
{
index = j;
max = arr[j];
}
}
temp = arr[n - i - 1];
arr[n - i - 1] = arr[index];
arr[index] = temp;
}
display(arr, n);
}
//插入排序,與初始化次序有關
void insert_sort(int * arr, int n)
{
if( NULL == arr ||n < 1)
return;
int temp;
for(int i = 1; i < n; ++i)
{
temp = arr[i];
int j;
for(j = i - 1; j >= 0&& arr[j] > temp; --j)
{
arr[j + 1] = arr[j];
}
arr[j + 1] = temp;
}
display(arr, n);
}
//希爾排序
void shell_sort(int *arr, int n)
{
int d, i, j, temp;
for(d = n/2; d >= 1; d = d/2)
{
for(i = d; i < n; ++i)
{
temp = arr[i];
for(j = i - d; j >= 0&&arr[j] > temp; j = j - d)
{
arr[j + d] = arr[j];
}
arr[j + d] = temp;
}
}
display(arr,n);
}
//歸併排序
void merge_sort(int * arr, int begin, int end, int * temp)
{
if(begin < end)
{
int mid = (begin + end )/2;
merge_sort(arr,begin,mid,temp);
merge_sort(arr,mid + 1,end,temp);
merge_array(arr,begin,mid,end,temp);
}
}
//二路歸併左右有序的數組
void merge_array(int *arr,int begin, int mid, int end, int *temp)
{
int i = begin, j = mid + 1, m = mid, n = end, k = 0;
while(i <= m &&j <= n)
{
if(arr[i] <= arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
}
}
while(i < m)
temp[k++] = arr[i++];
while(j < n)
temp[k++] = arr[j++];
for(i = 0; i < k; ++i)
arr[begin + i] = temp[i];
}
void MergeSort(int *arr, int n)
{
int *p = new int[n];
if (NULL == p)
return;
merge_sort(arr, 0, n - 1, p);
display(arr,n);
delete[] p;
}
//快速排序
void quick_sort(int *arr, int begin, int end)
{
if(begin < end)
{
int i = begin, j = end;
int temp = arr[i];
while(i < j)
{
while(i < j&&arr[j--] > temp)
;
arr[i] = arr[j];
while(i < j&&arr[++i] < temp)
;
arr[j] = arr[i];
}
arr[i] = temp;
quick_sort(arr,begin,i - 1);
quick_sort(arr,i +1,end);
}
}
void QuickSort(int *arr, int n)
{
quick_sort(arr, 0, n - 1);
display(arr, n);
}
//顯示輸出數組
void display(int *arr, int n)
{
//for(int i = 0; i < n; ++i)
//{
// cout<<arr[i]<<" ";
//}
cout<<endl;
}
//隨機產生1到n 的整數
long random(long n)
{
return (long)(n*rand()/(RAND_MAX+1.0)) + 1;
}
"test.cpp":
#include"sort_algorithms.h"
int main()
{
int num = 100000;
int * arr = new int[num];
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
clock_t start,end;
start=clock();
cout<<"冒泡排序:"<<endl;
bubble_sort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
start=clock();
cout<<"選擇排序:"<<endl;
choose_sort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
start=clock();
cout<<"插入排序:"<<endl;
insert_sort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
start=clock();
cout<<"希爾排序:"<<endl;
shell_sort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
start=clock();
cout<<"歸併排序:"<<endl;
MergeSort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
for(int i = 0; i < num; ++i)
arr[i] = random(10*num);
start=clock();
cout<<"快速排序:"<<endl;
QuickSort(arr,num);
end=clock();
cout<<num<<"個數排序花了: "<<end - start<<" 毫秒"<<endl;
cout<<"======================================================"<<endl;
delete arr;
return 0;
}
以下兩次運行隨機產生100000個1-1000000的整數的排序結果:
下面是運行第二次的結果:
針對希爾排序、歸併排序、快速排序,我還運行了一次隨機產生一億個一到十億間的數字進行排序,其他3個排序效率太低,運行時間太長,所以註釋掉了,結果如下:
從以上的結果可以看出,從時間角度看,快速排序確實是評價最優的。時間複雜度爲0(n*n)在處理大量數據的排序中確實很難滿足需求,時間成本太高。下面給出一個在百度百科上找到的總結性的圖表:
關於堆排序和基礎排序尚未給出具體實現的代碼,日後有時間再行補充。
寫此博客,重在與大家分享,共同學習,相互提高,如有疑問或建議,請留言。