【C++】各種排序執行時間的測試
我們經常見的就是對一組資料進行排序,而排序的方法有很多種。
常見的排序方法有:
氣泡排序,插入排序,希爾排序,快速排序,堆排序,選擇排序,歸併排序,計數排序,基數排序。
這些常見的排序方法,對同一組資料進行排序的時候有塊也又慢,它們的時間複雜度也不一樣:
接下來我們就來簡單的測試一下執行這些排序方法所需要的時間。
首先,計算一個程式執行的時間的函式是clock'函式,它放在time,h裡面。
我們在開始執行程式的時候定義start,執行完程式的時候定義一個finish,兩個時間相減,則可以得到該程式執行的時間 。
程式碼實現:
test.h檔案
#pragma once
#include <iostream>
using namespace std;
#include <time.h>
#include<assert.h>
#include<stack>
#define M 100 /* 執行次數 */
#define N 500 /* 陣列大小 */
void Menu();//選單函式
void BubbleSort(int *a, size_t n);//1,氣泡排序
void InsertSort(int *a, size_t n);//2,插入排序
void SheelSort(int *a, size_t n);//3,希爾排序
void SelectSort(int *a, size_t n);//4,選擇排序
void QuickSort(int *a, size_t left, size_t right);//5,快速排序演算法
void HeapSort(int *a, size_t n);//6,堆排序
void MergeSort(int* a, size_t n);//7,歸併排序
void CountSort(int *a, size_t n);//8,計數排序
void LSDSort(int *a, size_t n);//9,基數排序
test.cpp檔案
#include"test.h"
void Menu()
{
cout << "**********************************************\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 << "*******************0,退出********************\n";
cout << "**********************************************\n";
cout << "請選擇一種排序的演算法: " << endl;
}
//1,氣泡排序
void BubbleSort(int *a, size_t n)
{
int i, j;
int tmp;
for (i = 1; i < n; i++)
{
for (j = n-1; j >= i; j--)
{
if (a[j + 1] < a[j])
{
tmp = a[j + 1];
a[j + 1] = a[j];
a[j] = tmp;
}
}
}
}
//2,插入排序
void InsertSort(int *a, size_t n)
{
int i;
int j;
for (i = 2; i <= n; i++)
{
a[0] = a[i];
j = i - 1;
while (a[0] < a[j])
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = a[0];
}
}
//3,希爾排序
void SheelSort(int *a, size_t n)
{
assert(a);
int gub = n / 2;//先定義增量為n/2
while (gub > 0)
{
for (size_t i = gub; i < n; ++i)//從第gub個數據處開始進行交換
{
int tmp = a[i];
int end = i - gub;
while (end >= 0 && tmp < a[end])
{
a[end + gub] = a[end];
end = end - gub;
}
a[end + gub] = tmp;
}
gub /= 2;
}
}
//4,選擇排序
void SelectSort(int *a, size_t n)
{
assert(a);
int left = 0;
int right = n - 1;
while (left < right)
{
size_t MinIndex = left;
size_t MaxIndex = right;
for (size_t i = left; i <= right; ++i)
{
if (a[i] < a[MinIndex])
{
MinIndex = i;
}
if (a[i] > a[MaxIndex])
{
MaxIndex = i;
}
}
swap(a[left], a[MinIndex]);
if (MaxIndex == left)
{
MaxIndex = MinIndex;
}
swap(a[right], a[MaxIndex]);
++left;
--right;
}
}
//5,快速排序演算法
int PartSort(int *a, size_t left, size_t right)
{
int i, j;
static int w = 0;
int temp;
i = left;
j = right;
temp = a[i];
do
{
while ((a[j]>temp) && (i<j))
{
j--;
w++;
}
if (i<j)
{
a[i] = a[j];
i++;
w++;
}
while ((a[i]<= temp) && (i<j))
{
i++;
w++;
}
if (i<j)
{
a[j] = a[i];
j--;
w++;
}
} while (i != j);
a[i] = temp;
return i;
}
void QuickSort(int *a, size_t left, size_t right)
{
assert(a);
if (left >= right)
{
return;
}
int div = PartSort(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
//6,堆排序
void AdjustDown(int *a, size_t n, int root)
{
size_t parent = root;
size_t child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
++child;
}
if (a[child] > a[parent])
{
swap(a[child], a[parent]);
parent = child;;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int *a, size_t n)
{
assert(a);
int parent = (n - 2) >> 1;
//建堆
for (; parent >= 0; --parent)
{
AdjustDown(a, n, parent);
}
for (int i = n - 1; i >= 0; --i)
{
swap(a[0], a[i]);
AdjustDown(a, i, 0);
}
}
//7,歸併排序
void _MergeSort(int* src, int* dst, int left, int right)
{
if (left >= right)
return;
int mid = left + (right - left) / 2;
//[left,mid],[mid+1,right]
_MergeSort(src, dst, left, mid);
_MergeSort(src, dst, mid + 1, right);
int begin1 = left; int begin2 = mid + 1;
int index = 0;
while (begin1 <= mid && begin2 <= right)
{
if (src[begin1] < src[begin2])
dst[index++] = src[begin1++];
else
dst[index++] = src[begin2++];
}
while (begin1 <= mid)
dst[index++] = src[begin1++];
while (begin2 < right)
dst[index++] = src[begin2++];
int i = 0; int j = left;
while (i < index)
src[j++] = dst[i++];
}
void MergeSort(int* arr, size_t len)
{
assert(arr);
assert(len > 0);
int *tmp = new int[len];
_MergeSort(arr, tmp, 0, len - 1);
}
//8,計數排序
void CountSort(int *a, size_t n)
{
int i, j, k;
int C[N + 1] = { 0 }; /*用於計數的C陣列的所有元素初值為0*/
for (i = 0; i<n; i++)
C[a[i]]++; /*例如,R[i].key為6時,C[6]++,C[R[i].key]是R[i].key出現的次數*/
k = 0;
for (j = 0; j <= N; j++) /*考察每一個j*/
for (i = 1; i <= C[j]; i++) /*j=R[j].key出現過C[j]個,此即是排序的結果*/
a[k++] = j;
}
//9,基數排序
size_t GetMaxDigit(int *a, size_t n)
{
size_t digit = 1;
size_t base = 10;
for (size_t i = 0; i < n; i++)
{
while (a[i] >= base)
{
base *= 10;
digit++;
}
}
return digit;
}
void LSDSort(int *a, size_t n)
{
size_t maxDigit = GetMaxDigit(a, n);
size_t base = 1;
size_t *bucket = new size_t[n];
while ((maxDigit--) > 0)
{
size_t counts[10] = { 0 };
size_t start[10] = { 0 };
start[0] = 0;
for (size_t i = 0; i < n; i++)
{
size_t num = (a[i] / base) % 10;
counts[num]++;
}
for (size_t i = 1; i < 10; i++)
{
start[i] = start[i - 1] + counts[i - 1];
}
for (size_t i = 0; i < n; i++)
{
size_t num = (a[i] / base) % 10;
bucket[start[num]++] = a[i];
}
memcpy(a, bucket, sizeof(size_t)*n);
base *= 10;
}
}
main.cpp
#include"test.h"
void main()
{
int a[N], i, j, p;
Menu();
do{
cin >> p;
double start, finish; /* 定義開始的時間和結束的時間 */
start = (double)clock();
for (j = 0; j<M; j++)
{ /* 執行M次 */
for (i = 0; i<N; *(a + i++) = rand() % 10); /* 每次對陣列進行重新賦值 */
switch (p)
{
case 1:BubbleSort(a, N);
break;
case 2:InsertSort(a, N);
break;
case 3:SheelSort(a, N);
break;
case 4:SelectSort(a, N);
break;
case 5:QuickSort(a, 0, N - 1);
break;
case 6:HeapSort(a, N);
break;
case 7:MergeSort(a, N);
break;
case 8:CountSort(a, N);
break;
case 9:LSDSort(a, N);
case 0:break;
default:break;
}
}
finish = (double)clock();
printf("%.4fms\n", (finish - start));
} while (p != 0);
}
在本個小測試中,一共測試了九個排序方法:氣泡排序,插入排序,希爾排序,選擇排序,快速排序,堆排序,歸併排序,計數排序,基數排序。
接下來我們來看一下測試的結果:
由執行的結果可以得出結論:
由這個簡單的小測試,我們可以知道,排序中最快的是計數排序,然後是基數排序,氣泡排序是執行時間最長的一個方法。
這只是一個簡單的小測試,還有不完善的地方,望多多指教!
相關推薦
【C++】各種排序執行時間的測試
我們經常見的就是對一組資料進行排序,而排序的方法有很多種。 常見的排序方法有: 氣泡排序,插入排序,希爾排序,快速排序,堆排序,選擇排序,歸併排序,計數排序,基數排序。 這些常見的排序方法,對同一組資料進行排序的時候有塊也又慢,它們的時間複雜度也不一樣: 接下來我們就來簡
【初賽】各種排序演算法總結
一、演算法評價 排序方法 平均時間 最好時間 最壞時間 氣泡排序(穩定) O(n^2) O(n) O(n^2) 選擇排序(
【C++】併發-1 執行緒管理-1
【建立】 有四種方式: 預設 傳入執行函式 定義一個類, 過載 operator() ,執行緒執行過程 lambda // std::thread 簡單使用 namespace T1 { template<class T> class Thread
【C#】氣泡排序、隱式和顯式轉換、函式及異常處理
一、普通氣泡排序: C#中常見的排序方法有:氣泡排序,快速排序,插入排序,選擇排序、堆排序以及歸併排序。雖然還沒學習過,但是也有耳聞,就先把它們先歸類。今天主要講這裡面最常見的氣泡排序。 【概念】 氣泡排序也就是講一組需要排序的數,進行從小到大,或從大到小的排列。計算機
【OpenCV】測算程式碼執行時間
OpenCV 有一個非常實用的函式可以用來測算函式或程式碼段的執行時間,它就是 cv::get TickCount() , 該函式會返回從最近一次計算機開機到當前的時鐘週期數。 在程式碼開始和結 束時記錄這個時鐘週期數,就可以計算程式碼的執行時間。 若想得到以秒為單位的程
【opencv】獲取程式執行時間
double t = (double)getTickCount(); // do something ...返回該處程式碼執行所耗的時間,單位為秒 t = ((double)getTickCount(
【C#】 陣列排序和取值練習
1.從鍵盤接收一行用逗號分隔的5個整數,儲存至有5個元素的陣列中。 2.分別輸出正序和逆序的結果。 3/輸出陣列最大值和平均值,平均值保留1位小數。 4.存在非法輸入時顯示提示訊息並可重新輸入資料。 5.按下回車鍵退出,任意鍵繼續輸入。 輸出結果如圖所示。 -------
【C++】C++中幾種測試程式執行時間的方法
關於C++中計算時間的一些總結 一、使用GetTickCount()函式 GetTickCount()是一個函式,可以把它理解為打點計時器。GetTickCount()是通過計算從函式開始執行計時
【C++】測試時間
為了精準的獲取程式塊的執行時間,使用sys/time.h進行時間測試。 struct timeval start; struct timeval end; unsigned long Time = 0;
【C#】datetimepicker裡面如何設定日期為當天日期,而時間設為0:00或23:59?
今天無意中發現要根據日期查詢時間,datatimepicker控制元件會把時間預設成當前時間(當你的控制元件只顯示日期時),這樣查詢出來的出來的資料會有誤差,用來下面的辦法成功設定日期為當天日期,而時間設為0:00或23:59。 1 2 3 4 5 6 /
【C#】C#執行緒_I/O限制的非同步操作
目錄結構: contents structure [+] 為什麼需要非同步IO操作 C#的非同步函式 async和await的使用 非同步函式的狀態機 非同步函式如何轉化為狀態機 如何擴充套件非
【C#】獲取日期時間
前言 我們在機房重構的時候,我們經常會用到獲取時間和日期的操作! 我們可以通過使用DataTime這個類來獲取當前的時間。通過呼叫類中的各種方法我們可以獲取不同的時間:如:日期(2008-09-04)、時間(12:12:12)、日期+時間(2008-09-04 12:11:10)等。 時
【初探】“ 選擇排序 ” ——C++程式碼實現
選擇排序(Selection sort)是一種簡單直觀的排序演算法。無論什麼資料進去都是 O(n²) 的時間複雜度。所以用到它的時候,資料規模越小越好。唯一的好處可能就是不佔用額外的記憶體空間了吧。 簡單排序處理流程 首先在未排序序列中找到最小
【C】main (int argc,char *argv[]) 或main (int argc,char **argv)後臺(CMD下)執行說明
文章目錄 main (int argc,char *argv[]) 或main (int argc,char **argv)後臺(CMD下)執行說明 說明 一、main (int argc,char *argv[]) 或mai
【C++】編譯、連結、執行原理+強弱符號
【C++】編譯、連結、執行原理+強弱符號 虛擬地址空間 作用:程序地址空間需要隔離,防止惡意的程式修改其他程式的記憶體資料,所以計算機需要虛擬地址空間 其中: .data:已經初始化,並且初始化不為0的資料。 .bss:未初始化,或者初始化為0的資料。 例如: #i
【C#】C#執行緒_混合執行緒的同步構造
目錄結構: contents structure [+] 一個簡單的混合鎖 FCL中的混合鎖 ManualResetEventSlim類和SemaphoreSlim類 Monitor類和同步塊 ReaderWriterLockSlim類
【C#】List多權重排序
List.Sort((x, y) => -x.CompareTo(y)); 倒序排序 List.Sort((x, y) => x.CompareTo(y)); 正序排序 如果需要比較多個條件,比如裝備排序:橙>紫>藍,品質越高
【C#】【xUnit】【Moq】.NET單元測試Mock框架Moq初探!
在TDD開發模型中,經常是在編碼的同時進行單元測試的編寫,由於現代軟體開發不可能是一個人完成的工作,所以在定義好介面的時候我們就可以進行自己功能的開發(介面不能經常變更),而我們呼叫他人的功能時只需要使用介面即可。 但我們在編寫自己的單元測試並進行功能驗證的時候,如果介面的實現人還沒有完成程式碼怎麼
【java】各種Map中keySet()返回值的排序問題
上回說到,由於對資料進行處理的時候是按照亂序一行一行的處理,導致並行執行緒各自佔據了一部分資料,誰也不肯釋放,從而發生死鎖。 為什麼會亂序,是因為取得資料行主鍵的時候,使用了HashMap.keySet()方法,而這個方法返回的Set結果,裡面的資料是亂序排放的。 Jav
【leetcode】從排序陣列中刪除重複項(C、Python解答)
題目: 給定一個排序陣列,你需要在原地刪除重複出現的元素,使得每個元素只出現一次,返回移除後陣列的新長度。 不要使用額外的陣列空間,你必須在原地修改輸入陣列並在使用 O(1) 額外空間的條件下完成。 示例 1: 給定陣列 nums = [1,1,2], 函式應該