冒泡排序和qsort函数详解以及如何模拟实现qsort函数
一.冒泡排序
冒泡排序是一種常見的排序方式,它可以把數組元素有序或無序的數組進行重新排序,并使得數組中的元素從大到小或從小到大進行排序(就像泡泡一樣)。
冒泡排序原理:
每次比較數組中的相鄰的兩個元素的值,將較小的元素排在較大的元素的前面,就可實現數組元素從小到大排序;每次將較大的元素排在較小的元素的前面,就可實現數組元素從大到小排序。
以數字1,2,7,3,9,6為例,使其從大到小排序
對上表進行分析:
?? 第一次排序將最大的數字移動到第一第一元素[0]的位置,并將其它數字以次向后移動;第二次排序中,從第二個數字開始從剩余數字中挑選最大的數字,并將其移動到第二個位置,剩余數字依次向后移動;以此類推,可將數字1,2,7,3,9和6從大到小排列。
代碼實現:
#include<stdio.h>int main() {int arr[10] = { 0 };int i = 0, j = 0, tmp = 0;for (i = 0; i < 10; i++){scanf("%d", &arr[i]);//依次輸入你想排列的數字}for (i = 9; i >= 1; i--){for (j = i; j >= 1; j--){if (arr[j] > arr[j - 1]){tmp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = tmp;}}}for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;return 0; }對上述代碼進行分析:
我們可以看到總共有6個數字元素,單卻只排序5次。在最后依次排序過程2與1交換了位置剛好滿足從大到小排列,也就是說該數組你設置了n個元素那就要排序n -1次。
那依次排序中數組中的元素交換了多少次呢?
由圖表可知,在第一次排序中,我們可以觀察到【6,9】,【9,3】,【9,7】,【9,2】,【9,1】格一次總共是五次;在第二次排序中,因為我們已經知道9為最大值并且排在了[0]位置,所以9可以不用交換了,只需交換9后面的數字元素即可,這時總共交換了4次。以此類推可知第五次只需交換一次。由此可知,每次排序之后,數組元素需交換的次數都會減一。所以在代碼實現中我套用了兩層循環一層for(i=9;i>=1;i--)就是要排序的次數,另一層for(j=i;j>=1;j--)就是每次排序中需交換的次數。而j>=1這個判斷條件是為了防止數組越界的。(因為如果j=0的話arr[j-1]就越界了)
二.qsort函數詳解
??? qsort函數是C語言標準庫中的一種庫函數,它的作用就是快速排序,而要使用它的話就需要引用頭文件#include<stdlib.h>。
??? qsort的函數原型:
??? void qsort (void* base,size_t num,size_t size,int (* compar) (const void*e1,const void*e2)
??? 現在對qsort函數原型進行分析:
??? 1.void qsort:
??? 這個void代表qsort函數是一個無返回類型的函數。
??? 2.void* base:
??? 這個void*代表著是base的類型。base被官方解釋為指向要排序的數組的第一個對象的指針,轉換為空*。也就是說base,其實就是數組首元素的地址。
??? 具體實現:int values[6]={40,10,100,90,20,25};
????????????????????? qosrt(values,6,sizeof(int),compare);
??? 3.size_t num:
??? 這個size_t代表著是num的類型(size_t其實就是unsigned int 無符號整型),在官方的解釋中num是按基數指向數組中的元素數,也就是說num就是你傳給qsort這個函數的數組中的元素個數
??? 具體實現: qosrt(values,6,sizeof(int),compare);這個6就是num。
??? 4.size_t size
??? size_t同上,size在官方的解釋中就是數組中每個元素的大小(以字節為單位)。
??? 具體實現: qosrt(values,6,sizeof(int),compare);這個sizeof(int)就是int類型的值在內存中占多少個字節,因為數組values就是int類型的數組。
??? 5.int (*compare)(const void*e1,const void*e2)
??? 現在對上式進行分析。這是一個返回值類型為整型的函數指針,其中compare函數的兩個參數的類型為const void*。而在官方的解釋中這是一個指向比較兩個元素大小的函數指針。
??? 在qsort函數中的compare函數的使用方式類似于strcmp函數,qsort函數主要是通過compare函數的返回值來判斷傳入compare函數的兩個元素的值的大小關系。如果返回值小于零的話那么元素e1就小于e2;如果返回值等于零的話e1==e2;如果返回值大于零的話e1就大于e2。
??? 也就是說compare函數就是一種比較方法,用來比較傳入compare函數的兩個值的大小的。
?這個圖片就是官方給出的解釋。
綜上,qosrt的使用就是這樣的:
qsort(數組名,數組元素個數,數組每個元素的大小(以字節為單位),比較函數)
代碼實現:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h>int compare(void* e1, void* e2) {return (*(int*)e1 - *(int*)e2);//把e1,e2強制轉換為(int*)類型的因為傳到數組的元素就是int類型的。 }int main() {int arr[10] = { 0 };for (int i = 0; i < 10; i++){scanf("%d", &arr[i]);}qsort(arr, 10, sizeof(arr[0]), compare);//總結就是 qsort(數組名,數組元素個數,數組每個元素的大小(以字節為單位),比較函數)for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0; }?
運行結果:
?
三.qosrt函數的模擬實現
通過觀察qsort函數的代碼實現以及函數原型,我們可以仿照出一個類似的函數,這個函數必須要具備qsort函數的所有功能。
我先設這個函數名稱為bubble_sort,很多人可能會問,為什么我要把冒泡函數與qsort函數一起講?等會你們就知道了。
我們既然要讓bubble_sort實現qsort的功能那么在bubble_sort函數內部必然有一個排序語句來幫助bubble_sort這個函數正真實現快速排序,而冒泡排序法就是這個函數內部的的排序語句。但是qsort函數的模擬實現最主要也是最難的就是數組元素的交換,因為它涉及到了函數指針和強制類型轉換,不多bb直接上代碼然后解釋一下具體怎么交換數組元素。
代碼實現:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>int compare(void* e1, void* e2) {return (*(int*)e1 - *(int*)e2); } void bubble_sort(int* p, size_t num, size_t size, int(*compare)(void* e1, void* e2)) {int i = 0, j = 0;for (i = num - 1; i >= 1; i--){for (j = 0; j < i; j++){if (compare((char*)p+j*size,(char*)p+(j+1)*size) > 0){int x = 0;char tmp;for (x = 0; x < size; x++){tmp = *((char*)p + j * size+x);*((char*)p + j * size+x) = *((char*)p + (j + 1) * size+x);*((char*)p + (j + 1) * size+x) = tmp;}}}} } int main() {int arr[10] = { 0 };for (int i = 0; i < 10; i++){scanf("%d", &arr[i]);}bubble_sort(arr, 10, sizeof(arr[0]), compare);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0; }為了使我們模擬實現的bubble_sort函數能夠排序多種類型包括整型(int,short,long,long),字符型(char)以及實型也叫浮點型(float,double),所以我們需要把數組元素強制轉換為char*類型。
在上述代碼中我們可以看到compare((char*)p+j*size,(char*)p+(j+1)*size),這里傳過去的的是(char*)p+j*size和(char*)p+(j+1)*size,在這里如果我們只傳(char*)p是顯然行不通的,因為p這個地址就是數組arr的首元素地址,因為我們需要交換數組里面的所有元素所以我們就要傳兩個相鄰的數組元素,而這兩個元素會隨著循環次數增加而改變。如j=0是(char*)p+j*size實際上就是arr[0],(char*)p+(j+1)*size顯然就是arr[1]了,而隨著j增加傳過去的元素也會改變。(其中size就是數組元素的大小,而(char*)p加了j*size,地址p就會向后移動j*size個字節,也就是arr[]的下標會移動加j)。
而*((char*)p+j*size+x)和*((char*)p+(j+1)*size+x)其實就是對(char*)p+j*size+x以及后者的解引用而言,這里值得注意的是x,為什么要加x?是因為p已經被強制類型轉換成了char*型的所以我們為了交換數組元素就要一個字節一個字節的交換(char類型占內存是1個字節,int是4個字節)。而且這個加x就是使p向后位移x位。
ps:compar函數傳過去的參數應該是兩個指針。
總結
以上是生活随笔為你收集整理的冒泡排序和qsort函数详解以及如何模拟实现qsort函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ksweb 设置伪静态
- 下一篇: JASS萌新学习指南1.4(被催更)