日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

常用排序算法总结(C语言版)

發(fā)布時(shí)間:2024/1/1 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常用排序算法总结(C语言版) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 一、排序算法概覽
  • 二、算法實(shí)現(xiàn)
    • 1、選擇排序
    • 2、冒泡排序
    • 3、插入排序
    • 4、快速排序
    • 5、希爾排序
    • 6、桶排序(基數(shù)排序)
    • 7、歸并排序
    • 8、堆排序
  • 三、總結(jié)


一、排序算法概覽


可以在VisuAlgo或者站長(zhǎng)輔助工具中查看這些排序算法的動(dòng)態(tài)演示過(guò)程

二、算法實(shí)現(xiàn)

1、選擇排序

選擇排序(Selection sort)是一種簡(jiǎn)單直觀的排序算法。它的工作原理是每一次從待排序的數(shù)據(jù)元素中選出最小(或最大)的一個(gè)元素,存放在序列的起始位置,直到全部待排序的數(shù)據(jù)元素排完。 選擇排序是不穩(wěn)定的排序方法。

void selectSort(ElemType arr[], int len) //選擇排序 {int temp;for (int i = 0; i < len - 1; ++i){for (int j = i + 1; j < len; ++j){if (arr[i]>arr[j]){temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}} }

2、冒泡排序

冒泡排序(Bubble Sort),是一種計(jì)算機(jī)科學(xué)領(lǐng)域的較簡(jiǎn)單的排序算法。它重復(fù)地走訪過(guò)要排序的數(shù)列,一次比較兩個(gè)元素,如果他們的順序錯(cuò)誤就把他們交換過(guò)來(lái)。走訪數(shù)列的工作是重復(fù)地進(jìn)行直到?jīng)]有再需要交換,也就是說(shuō)該數(shù)列已經(jīng)排序完成。這個(gè)算法的名字由來(lái)是因?yàn)樵酱蟮脑貢?huì)經(jīng)由交換慢慢“浮”到數(shù)列的頂端。

冒泡排序改進(jìn)1:在某次遍歷中如果沒(méi)有數(shù)據(jù)交換,說(shuō)明整個(gè)數(shù)組已經(jīng)有序。因此通過(guò)設(shè)置標(biāo)志位來(lái)記錄此次遍歷有無(wú)數(shù)據(jù)交換就可以判斷是否要繼續(xù)循環(huán)。

冒泡排序改進(jìn)2:記錄某次遍歷時(shí)最后發(fā)生數(shù)據(jù)交換的位置,這個(gè)位置之后的數(shù)據(jù)顯然已經(jīng)有序了。因此通過(guò)記錄最后發(fā)生數(shù)據(jù)交換的位置就可以確定下次循環(huán)的范圍了。

void bulletSort(ElemType arr[], int len) //冒泡排序 {int temp;for (int i = 0; i < len - 1; ++i){for (int j = 0; j < len - 1 - i; ++j){if (arr[j]>arr[j + 1]){temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}

3、插入排序

插入排序基本操作就是將一個(gè)數(shù)據(jù)插入到已經(jīng)排好序的有序數(shù)據(jù)中,從而得到一個(gè)新的、個(gè)數(shù)加一的有序數(shù)據(jù),算法適用于少量數(shù)據(jù)的排序,時(shí)間復(fù)雜度為O(n^2)。是穩(wěn)定的排序方法。插入排序的基本思想是:每步將一個(gè)待排序的紀(jì)錄,按其關(guān)鍵碼值的大小插入前面已經(jīng)排序的文件中適當(dāng)位置上,直到全部插入完為止。

void insertSort(ElemType arr[], int len) //插入排序 {int temp,j,i;//形式1for (i = 1; i < len; ++i){temp = arr[i];j = i - 1;while (j >= 0 && temp < arr[j])//j指向的是有序序列{arr[j + 1] = arr[j];--j;} arr[j + 1] = temp;}//形式2//for (i = 1; i < len; ++i)//{// temp = arr[i];// for (j = i - 1; j >= 0 && temp < arr[j]; --j)//j指向的是有序序列// {// arr[j + 1] = arr[j];// }// arr[j + 1] = temp;//}//形式3/*for (i = 1; i < len; ++i){temp = arr[i];for (j = i - 1; j >= 0; --j){if (temp < arr[j]){arr[j + 1] = arr[j];}elsebreak;}arr[j + 1] = temp;}*///形式4/*for (int i = 1; i < len; ++i){for (int j = i - 1; j >= 0; --j){if (arr[j + 1] < arr[j]){temp = arr[j + 1];arr[j + 1] = arr[j];arr[j] = temp;}elsebreak;}}*/ }

4、快速排序

快速排序(Quicksort)是對(duì)冒泡排序的一種改進(jìn)。它的基本思想是:通過(guò)一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對(duì)這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序,整個(gè)排序過(guò)程可以遞歸進(jìn)行,以此達(dá)到整個(gè)數(shù)據(jù)變成有序序列。

void quickSort(ElemType arr[], int left, int right)//快速排序 {int i = left, j = right;int temp;if (left >= right) return;while (i <= j){while (i <= j&&arr[left] >= arr[i]) ++i;//找出左邊比arr[left]大的元素while (i <= j&&arr[left] <= arr[j]) --j;//找出右邊比arr[left]小的元素if (i < j)//交換找到的元素{temp = arr[i];arr[i] = arr[j];arr[j] = temp;i++;//交換完之后移向下一個(gè)位置--j;}}//經(jīng)過(guò)循環(huán)后在j位置就是標(biāo)桿的位置,這個(gè)位置左邊都不大于該值,該位置右邊都不小于該值temp = arr[left];arr[left] = arr[j];arr[j] = temp; //交換quickSort(arr, left, j - 1); //遞歸操作左邊元素quickSort(arr, j+1, right); //遞歸操作右邊元素}

5、希爾排序

希爾排序(Shell Sort)是插入排序的一種。也稱(chēng)縮小增量排序,是直接插入排序算法的一種更高效的改進(jìn)版本。希爾排序是非穩(wěn)定排序算法。希爾排序是把記錄按下標(biāo)的一定增量分組,對(duì)每組使用直接插入排序算法排序;隨著增量逐漸減少,每組包含的關(guān)鍵詞越來(lái)越多,當(dāng)增量減至1時(shí),整個(gè)文件恰被分成一組,算法便終止。

void shellSort(ElemType arr[], int len) //希爾排序 {int d = len / 2; //分組(增量置初值)int i, j;int temp;while (d > 0) //由希爾排序要進(jìn)行的次數(shù)來(lái)決定(每一次都有相應(yīng)的分組情況,即有不同的增值){for (i = d; i < len; ++i) // 對(duì)該次希爾排序(分組情況)進(jìn)行插入排序(由要進(jìn)行插入排序的元素個(gè)數(shù)來(lái)決定)//本來(lái)一個(gè)插入排序從1開(kāi)始,這里有d組插入排序,所以從d開(kāi)始 //這個(gè)是d組一起進(jìn)行插入排序,即等到每一組都插入第i個(gè)元素后,才會(huì)進(jìn)行插入第i+1個(gè)元素{temp = arr[i];for (j = i - d; j >= 0 && temp < arr[j]; j = j - d) //將每次的元素插入(由有序元素的個(gè)數(shù)來(lái)決定)arr[j + d] = arr[j];arr[j + d] = temp;}d = d / 2; //從新分組} }

6、桶排序(基數(shù)排序)

基數(shù)排序,第一步根據(jù)數(shù)字的個(gè)位分配到每個(gè)桶里,在桶內(nèi)部排序,然后將數(shù)字再輸出(串起來(lái));然后根據(jù)十位分桶,繼續(xù)排序,再串起來(lái)。直至所有位被比較完,所有數(shù)字已經(jīng)有序。

void radixSort(ElemType arr[], int len)//桶排序(基數(shù)排序) {int temp[10][20];int index;for (int n = 1; n <= 100; n *= 10)//數(shù)據(jù)中最大數(shù)是幾位,就要進(jìn)行幾次循環(huán){for (int x = 0; x < 10; ++x) //初始化 為了方便查找到存放的數(shù)據(jù){for (int y = 0; y < 20; ++y){temp[x][y] = -1;}}for (int i = 0; i < len; ++i) //存放數(shù)據(jù){index = (arr[i] / n) % 10;temp[index][i] = arr[i];}int count = 0;for (int i = 0; i < 10; ++i) //將該次排序后的結(jié)果放回原數(shù)組{for (int j = 0; j < 20; ++j){if (temp[i][j] != -1)arr[count++] = temp[i][j];}}} }

7、歸并排序

歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個(gè)非常典型的應(yīng)用。將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱(chēng)為二路歸并。

void mergeInArr(ElemType arr[], int left, int mid, int right) {//注意此時(shí)左右空間都是各自有序int length = right - left + 1; //輔助數(shù)組長(zhǎng)度int *p = new int[length]; //構(gòu)建輔助數(shù)組memset(p, 0, sizeof(int)*length); //給輔助數(shù)組賦值int low = left; //記錄左區(qū)間的起始位置int hig = mid + 1; //記錄右區(qū)間的起始位置 int index = 0; //輔助空間下標(biāo)while (low <= mid&&hig <= right) //左右區(qū)間都沒(méi)有比較完,都有數(shù)據(jù){while (low <= mid&&arr[low] <= arr[hig])//如果左邊區(qū)間沒(méi)有越界,并且左區(qū)間的數(shù)值<=右區(qū)間的數(shù)值p[index++] = arr[low++]; //將小的數(shù)據(jù)存入輔助空間while (hig <= right&&arr[low] > arr[hig]) //如果右邊區(qū)間沒(méi)有越界,并且左區(qū)間的數(shù)值>右區(qū)間的數(shù)值p[index++] = arr[hig++]; //將小的數(shù)據(jù)存入輔助空間}//到這一步,證明起碼有一個(gè)區(qū)間是合并進(jìn)了輔助數(shù)組if (hig <= right)//證明右區(qū)間并沒(méi)有完成合并,左區(qū)間是完成合并,把右區(qū)間剩下的數(shù)據(jù)直接拷貝到輔助數(shù)組即可(此時(shí)右區(qū)間剩下的數(shù)據(jù)比輔助空間的數(shù)據(jù)大)memcpy(&p[index], &arr[hig], sizeof(int)*(right - hig + 1));if (low <= mid)memcpy(&p[index], &arr[low], sizeof(int)*(mid - low + 1));//將排完序的值傳回給原數(shù)組memcpy(&arr[left], p, sizeof(int)*length); //這里&arr[left]要特別注意,不能寫(xiě)成arrdelete[]p;}void merge(ElemType arr[], int left, int right) {int mid;if (left >= right) return; //遞歸出口 這里就不需要遞歸了mid = ((right - left) >> 1) + left; //查找到中間值 將數(shù)組分成兩部分 左區(qū)間和右區(qū)間//************ 歸操作 **********//merge(arr, left, mid); //左區(qū)間 merge(arr, mid + 1, right); //右區(qū)1間//************** 并操作 **************//mergeInArr(arr, left, mid, right); //將歸操作后單個(gè)有序區(qū)間合并}void mergeSort(ElemType arr[], int len) {merge(arr, 0, len - 1);//歸并排序 }

函數(shù)說(shuō)明
(1)使用以下函數(shù)需要加頭文件#include<memory.h>
(2)memset 函數(shù):內(nèi)存逐字節(jié)賦值,有三個(gè)參數(shù),第一個(gè)參數(shù)是哪個(gè)內(nèi)存,第二個(gè)參數(shù)賦什么值,第三個(gè)參數(shù)這個(gè)內(nèi)存需要賦多大的內(nèi)存。
(3)memcpy內(nèi)存拷貝函數(shù),有3個(gè)參數(shù),表示把第二個(gè)參數(shù)的首地址里面的內(nèi)容拷貝到第一個(gè)參數(shù)表示的首地址里面,拷貝大小為第三個(gè)參數(shù)表示的大小

8、堆排序

堆的插入就是——每次插入都是將新數(shù)據(jù)放在數(shù)組最后,而從這個(gè)新數(shù)據(jù)的父結(jié)點(diǎn)到根結(jié)點(diǎn)必定是一個(gè)有序的數(shù)列,因此只要將這個(gè)新數(shù)據(jù)插入到這個(gè)有序數(shù)列中即可。

堆的刪除就是——堆的刪除就是將最后一個(gè)數(shù)據(jù)的值賦給根結(jié)點(diǎn),然后再?gòu)母Y(jié)點(diǎn)開(kāi)始進(jìn)行一次從上向下的調(diào)整。調(diào)整時(shí)先在左右兒子結(jié)點(diǎn)中找最小的,如果父結(jié)點(diǎn)比這個(gè)最小的子結(jié)點(diǎn)還小說(shuō)明不需要調(diào)整了,反之將父結(jié)點(diǎn)和它交換后再考慮后面的結(jié)點(diǎn)。相當(dāng)于從根結(jié)點(diǎn)開(kāi)始將一個(gè)數(shù)據(jù)在有序數(shù)列中進(jìn)行“下沉”。

因此,堆的插入和刪除非常類(lèi)似直接插入排序,只不是在二叉樹(shù)上進(jìn)行插入過(guò)程。所以可以將堆排序形容為“樹(shù)上插”

更加詳細(xì)的過(guò)程可以查看博文:堆排序算法(圖解詳細(xì)流程)

//堆排序public static void heapSort(int[] arr) {//構(gòu)造大根堆heapInsert(arr);int size = arr.length;while (size > 1) {//固定最大值swap(arr, 0, size - 1);size--;//構(gòu)造大根堆heapify(arr, 0, size);}}//構(gòu)造大根堆(通過(guò)新插入的數(shù)上升)public static void heapInsert(int[] arr) {for (int i = 0; i < arr.length; i++) {//當(dāng)前插入的索引int currentIndex = i;//父結(jié)點(diǎn)索引int fatherIndex = (currentIndex - 1) / 2;//如果當(dāng)前插入的值大于其父結(jié)點(diǎn)的值,則交換值,并且將索引指向父結(jié)點(diǎn)//然后繼續(xù)和上面的父結(jié)點(diǎn)值比較,直到不大于父結(jié)點(diǎn),則退出循環(huán)while (arr[currentIndex] > arr[fatherIndex]) {//交換當(dāng)前結(jié)點(diǎn)與父結(jié)點(diǎn)的值swap(arr, currentIndex, fatherIndex);//將當(dāng)前索引指向父索引currentIndex = fatherIndex;//重新計(jì)算當(dāng)前索引的父索引fatherIndex = (currentIndex - 1) / 2;}}}//將剩余的數(shù)構(gòu)造成大根堆(通過(guò)頂端的數(shù)下降)public static void heapify(int[] arr, int index, int size) {int left = 2 * index + 1;int right = 2 * index + 2;while (left < size) {int largestIndex;//判斷孩子中較大的值的索引(要確保右孩子在size范圍之內(nèi))if (arr[left] < arr[right] && right < size) {largestIndex = right;} else {largestIndex = left;}//比較父結(jié)點(diǎn)的值與孩子中較大的值,并確定最大值的索引if (arr[index] > arr[largestIndex]) {largestIndex = index;}//如果父結(jié)點(diǎn)索引是最大值的索引,那已經(jīng)是大根堆了,則退出循環(huán)if (index == largestIndex) {break;}//父結(jié)點(diǎn)不是最大值,與孩子中較大的值交換swap(arr, largestIndex, index);//將索引指向孩子中較大的值的索引index = largestIndex;//重新計(jì)算交換之后的孩子的索引left = 2 * index + 1;right = 2 * index + 2;}}//交換數(shù)組中兩個(gè)元素的值public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}

三、總結(jié)

此處使用More Windows圖解來(lái)對(duì)上述的算法進(jìn)行總結(jié),如果對(duì)圖解中算法的含義不是很理解可以參考博文:各個(gè)排序算法的時(shí)間復(fù)雜度和穩(wěn)定性,快排的原理

排序圖表

More Windows圖解七種經(jīng)典的排序算法

總結(jié)

以上是生活随笔為你收集整理的常用排序算法总结(C语言版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。