C語(yǔ)言所有經(jīng)典排序方法的實(shí)現(xiàn)代碼
運(yùn)行結(jié)果正確
還是快速排序難一些。

完整代碼
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include<malloc.h>
void swap(int *a,int *b);
void select_sort(int arr[],int n);
void tra_arr(int arr[],int n);
void insert_sort(int arr[],int n);
void shell_sort(int arr[],int n);
void perc_down(int arr[],int i,int n);
void heap_sort(int arr[],int n);
void merge(int arr[],int temp_arr[],int left_start,int right_start
,int right_end);
void m_sort(int arr[],int temp_arr[],int left,int right);
void merge_sort(int arr[],int n);
int get_pri(int arr[],int left,int right);
void q_sort(int arr[],int left,int right);
void quick_sort(int arr[],int n);
int main(){
int arr[100]={
10,9,8,7,6,5,4,3,2,1
};
select_sort(arr,10);
printf("\n簡(jiǎn)單選擇排序結(jié)果\n");
tra_arr(arr,10);
int arr1[100]={
10,9,8,7,6,5,4,3,2,1
};
insert_sort(arr1,10);
printf("\n插入排序結(jié)果\n");
tra_arr(arr1,10);
int arr2[100]={
10,9,8,7,6,5,4,3,2,1
};
shell_sort(arr2,10);
printf("\n希爾排序結(jié)果\n");
tra_arr(arr2,10);
int arr3[100]={
10,9,8,7,6,5,4,3,2,1
};
heap_sort(arr3,10);
printf("\n堆排序結(jié)果\n");
tra_arr(arr3,10);
int arr4[100]={
10,9,8,7,6,5,4,3,2,1
};
merge_sort(arr4,10);
printf("\n歸并排序結(jié)果\n");
tra_arr(arr4,10);
int arr5[100]={
10,9,8,7,6,5,4,3,2,1
};
quick_sort(arr5,10);
printf("\n快速排序結(jié)果\n");
tra_arr(arr5,10);
return 0;
}
void swap(int *a,int *b){
//在函數(shù)內(nèi)部,如果打算接收的是指針的地址,那就不要加*,
//如果想要的是值,那就加*,我也很討厭指針,但是沒(méi)辦法
int t=*a;
*a=*b;
*b=t;
}
//簡(jiǎn)單選擇排序
void select_sort(int arr[],int n){
int min;
//這個(gè)過(guò)程一時(shí)半會(huì)講不清楚,看書(shū)會(huì)清楚一些
for(int i=0;i<n;i++){
min=i;
for(int j=i+1;j<n;j++){
if(arr[i]>arr[j]){
min=j;
}
}
//經(jīng)過(guò)上面的里層for,就找到了最小的元素的下表
swap(&arr[i],&arr[min]) ;
}
}
//插入排序
void insert_sort(int arr[],int n){
int temp,j;
for(int i=1;i<n;i++){
temp=arr[i];
for(j=i;j>0&&arr[j-1]>temp;j--){
//后挪
arr[j]=arr[j-1];
}
//現(xiàn)在就找到空出來(lái)的插入位置了
arr[j]=temp;
}
}
//希爾排序
void shell_sort(int arr[],int n){
int in,i,j,temp;
//本來(lái)這個(gè)排序是很好理解的,就是這個(gè)外層的循環(huán)
//故弄玄虛,你就把他理解成一個(gè)簡(jiǎn)單的,遞減的數(shù)組就行
//而且這個(gè)2的指數(shù)遞減的序列的時(shí)間復(fù)雜度是很壞的
//最好使用SED或者HIB序列會(huì)好很多,這里只是演示
//兩個(gè)里層的for就是插入排序,仔細(xì)看看就能看懂
for(in=n/2;in>0;in=in/2){
for(i=in;i<n;i++){
temp=arr[i];
for(j=i;j>=in;j=j-in){
if(arr[j-in]>temp){
//后挪
arr[j]=arr[j-in];
}
else{
//arr[j-in]<temp,說(shuō)明找到了
break;
}
}
//上面執(zhí)行完,肯定找到了插入位置
arr[j]=temp;
}
}
}
//首先是下濾操作
//i是根,n是heap的規(guī)模
//這里的下濾針對(duì)最大堆
void perc_down(int arr[],int i,int n){
int child,temp;
//仔細(xì)想想,其實(shí)和插入排序差不多
//首先把i取出來(lái),把i在堆里面所在的位置空出來(lái)
//這里和原來(lái)建堆的下濾又不一樣,這里沒(méi)有設(shè)置哨兵
for(temp=arr[i];(2*i+1)<n;i=child){
child=2*i+1;
//如果當(dāng)前兒子不是最后一個(gè),說(shuō)明還有右兒子
//兩者取最大
if(child!=(n-1)&&arr[child]<arr[child+1]){
child++;
}
if(temp<arr[child]){
arr[i]=arr[child];
}
else{
//當(dāng)前取出來(lái)的值終于大于兩個(gè)兒子時(shí)。
break;
}
}
//上面輪完之后,肯定找到了一個(gè)兒子比我們?nèi)〕鰜?lái)的值還要小的
arr[i]=temp;
}
void heap_sort(int arr[],int n){
int i;
//建堆
for(i=n/2;i>=0;i--){
perc_down(arr,i,n);
}
//取最大值放在最后已經(jīng)舍棄的位置上,下濾剩下的堆
for(i=n-1;i>0;i--){
//取最大值放在最后已經(jīng)舍棄的位置上
swap(&arr[0],&arr[i]);
// 濾剩下的堆
perc_down(arr,0,i);
}
}
//歸并排序
//第一步,寫(xiě)一個(gè)將兩個(gè)已經(jīng)排好序列的歸并
void merge(int arr[],int temp_arr[],int left_start,int right_start
,int right_end)
{
int i,temp_start,elem_num,left_end;
temp_start=left_start;
left_end=right_start-1;
elem_num=right_end-left_start+1;
//歸并的核心
while(left_start<=left_end&&right_start<=right_end){
if(arr[left_start]<=arr[right_start]){
temp_arr[temp_start++]=arr[left_start++];
}
else{
temp_arr[temp_start++]=arr[right_start++];
}
}
while(left_start<=left_end){
temp_arr[temp_start++]=arr[left_start++];
}
while(right_start<=right_end){
temp_arr[temp_start++]=arr[right_start++];
}
//重新拷回去,記住,這里歸并的只是原來(lái)數(shù)組的一部分,所以不能從頭開(kāi)始
for(i=0;i<elem_num;i++,right_end--) {
arr[right_end]=temp_arr[right_end];
}
}
//第二步,遞歸調(diào)用歸并,將數(shù)組不斷分割
void m_sort(int arr[],int temp_arr[],int left,int right){
//tra_arr(arr,10);
int center;
//遞歸結(jié)束條件
if(left<right){
center=(right+left)/2;
m_sort(arr,temp_arr,left,center);
m_sort(arr,temp_arr,center+1,right);
merge(arr,temp_arr,left,center+1,right);
}
}
//第三步,初始化臨時(shí)數(shù)組
void merge_sort(int arr[],int n){
int *temp_arr;
temp_arr=(int*)malloc(n*sizeof(int));
m_sort(arr,temp_arr,0,n-1);
free(temp_arr);
}
//快速排序
//首先,實(shí)現(xiàn)三數(shù)中值分割法,取一個(gè)“裁判” (中值)
int get_pri(int arr[],int left,int right){
int center=(left+right)/2;
if(arr[left]>arr[center]){
swap(&arr[left],&arr[center]);
}
if(arr[left]>arr[right]){
swap(&arr[left],&arr[right]);
}
if(arr[center]>arr[right]){
swap(&arr[center],&arr[right]);
}
//把中值扔到倒數(shù)第二個(gè),因?yàn)樯鲜霾僮饕呀?jīng)讓倒數(shù)第一大于中值了
swap(&arr[center],&arr[right-1]);
return arr[right-1];
}
//其次,實(shí)現(xiàn)分而治之
void q_sort(int arr[],int left,int right){
int i,j,pri;
//如果規(guī)模已經(jīng)小于三了,就不要再分而治之了,沒(méi)得分了
if(right-left>=3){
//取中值
pri= get_pri(arr,left,right);
//取左右往中間靠攏的兩個(gè)指針i,j
i=left;
j=right-1;
//開(kāi)始判斷
while(1){
//如果當(dāng)前i對(duì)應(yīng)的值小于裁判,繼續(xù)推進(jìn)
while(arr[++i]<pri);
// 如果當(dāng)前i對(duì)應(yīng)的值大于裁判,繼續(xù)推進(jìn)
while(arr[--j]>pri);
//上面走完,肯定碰到硬杈了,在i和j沒(méi)有錯(cuò)位的情況下
//交換
if(i<j){
swap(&arr[i],&arr[j]);
}
else{
break;
}
}
swap(&arr[i],&arr[right-1]);
//這個(gè)i的作用遠(yuǎn)不止此,這個(gè)i還記錄了上一個(gè)裁判的位置
//開(kāi)始對(duì)分下來(lái)的兩個(gè)部分進(jìn)行同樣的操作
q_sort(arr,left,i-1);
q_sort(arr,i+1,right);
}
//如果遞歸到規(guī)模已經(jīng)無(wú)法再分了
//就用普通的方法排序
else{
/*這里稍微講一下
數(shù)組和指針實(shí)際上是一樣的東西
到這里了,那肯定就剩一個(gè)或者兩個(gè)元素了
所以數(shù)組的開(kāi)頭變成left所指的位置,現(xiàn)在left所在位置的下標(biāo)
就是0,所以后面的n也要相應(yīng)變化*/
insert_sort(arr+left,right-left+1);
}
}
//最后包裝一下
void quick_sort(int arr[],int n){
q_sort(arr,0,n-1);
}
//遍歷數(shù)組
void tra_arr(int arr[],int n){
for(int i=0;i<n;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
以上就是C語(yǔ)言所有經(jīng)典排序方法的實(shí)現(xiàn)代碼的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言排序方法的的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解C語(yǔ)言快速排序三種方法的單趟實(shí)現(xiàn)
本文將通過(guò)圖片重點(diǎn)為大家介紹一下C語(yǔ)言中快速排序三種方法的單趟實(shí)現(xiàn):分別是hoare法、挖坑法、雙指針?lè)?,文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-06-06
C++精要分析右值引用與完美轉(zhuǎn)發(fā)的應(yīng)用
C++11標(biāo)準(zhǔn)為C++引入右值引用語(yǔ)法的同時(shí),還解決了一個(gè)短板,即使用簡(jiǎn)單的方式即可在函數(shù)模板中實(shí)現(xiàn)參數(shù)的完美轉(zhuǎn)發(fā)。那么,什么是完美轉(zhuǎn)發(fā)?它為什么是C++98/03 標(biāo)準(zhǔn)存在的一個(gè)短板?C++11標(biāo)準(zhǔn)又是如何為C++彌補(bǔ)這一短板的?別急,本節(jié)將就這些問(wèn)題給讀者做一一講解2022-05-05
C++單例模式實(shí)現(xiàn)線(xiàn)程池的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C++單例模式簡(jiǎn)單實(shí)現(xiàn)一個(gè)線(xiàn)程池,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04
C++超詳細(xì)講解標(biāo)準(zhǔn)庫(kù)
C++強(qiáng)大的功能來(lái)源于其豐富的類(lèi)庫(kù)及庫(kù)函數(shù)資源。C++標(biāo)準(zhǔn)庫(kù)(C++ Standard Library, 亦可稱(chēng)作,C++標(biāo)準(zhǔn)程序庫(kù))的內(nèi)容總共在50個(gè)標(biāo)準(zhǔn)頭文件中定義。在C++開(kāi)發(fā)中,要盡可能地利用標(biāo)準(zhǔn)庫(kù)完成2022-06-06
Qt使用TabWidget實(shí)現(xiàn)多窗體功能
Qt 是一個(gè)跨平臺(tái)C++圖形界面開(kāi)發(fā)庫(kù),利用Qt可以快速開(kāi)發(fā)跨平臺(tái)窗體應(yīng)用程序,在Qt中我們可以通過(guò)拖拽的方式將不同組件放到指定的位置,本章將重點(diǎn)介紹TabWidget標(biāo)簽組件的常用方法及靈活運(yùn)用,需要的朋友可以參考下2023-12-12
C利用語(yǔ)言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)之隊(duì)列
隊(duì)列 (Queue):簡(jiǎn)稱(chēng)隊(duì),是另一種限定性的線(xiàn)性表,它只允許在表的一端插入元素,而在另一端刪除元素。q=(a1, a2, a3, … an),其中a1為隊(duì)頭,an為隊(duì)尾,下面文章小編將為大家詳細(xì)介紹,需要的下伙伴可以參考一下2021-10-10

