摘要:目錄一函數(shù)是什么二使用排序以升序為例關于型指針整形數(shù)組排序字符數(shù)組排序字符指針數(shù)組排序結構體數(shù)組排序浮點型數(shù)組排序三使用冒泡排序思想模擬實現(xiàn)函數(shù)什么是冒泡排序冒泡排序代碼使用冒泡排序思想模
目錄
? ? ??關于void*型指針:
三.使用冒泡排序思想模擬實現(xiàn)qsort函數(shù)
3.?使用冒泡排序思想模擬實現(xiàn)qsort函數(shù)
我們可以使用??搜索庫函數(shù)網(wǎng)址或者MSDN軟件進行查找。
qsort()函數(shù):快速排序的函數(shù) ?-引用stdlib.h頭文件
參數(shù)說明:
void qsort (?? ? void* base, //要排序的目標數(shù)組
?? ?size_t num,?? ??//待排序的元素個數(shù)
?? ?size_t width,?? ?//一個元素的大小,單位是字節(jié)
?? ?int(*cmp)(const void* e1, const void* e2));?? ??? ?
其中cmp是函數(shù)指針,cmp指向的是:排序時,用來比較兩個元素的函數(shù)。需要自己編寫。
返回值:
????????
??void*:無具體類型的指針???能夠接收任意類型的地址
?缺點:不能進行運算。不能+-整數(shù),不能解引用
int a = 0;float f = 5.5f;void* p1 = &a;void* p2 = &f;p1 = p1+1; //err
注意:
1.比較函數(shù)的參數(shù)類型為void* ,我們要進行強制類型轉(zhuǎn)換!且要解引用才能得到對應的值!?
2.若我們想排成降序,只需要寫成e2-e1即可
void Print(int* arr, int sz){ int i = 0; for (i = 0; i < sz; i++) { printf("%d ", *(arr + i)); } printf("/n");}//比較整形//注意類型時void* 所以要強制類型轉(zhuǎn)化,還要解引用才是對應的值!!!int cmp_int(const void* e1, const void* e2){ return *(int*)e1 - *(int*)e2;}void test1(){ int arr[] = { 9,8,7,6,7,5,4,8 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp_int); Print(arr, sz);}
注意使用sizeof()操作符和strlen()函數(shù)的區(qū)別
//注意要要強制類型轉(zhuǎn)換!! 要解引用!!! 本質(zhì)上是比較Ascii值int cmp_char(const void* e1, const void* e2){ return *(char*)e1 - *(char*)e2;}void test4(){ char arr[] ="mango"; //若使用sizeof計算長度: //int sz = sizeof(arr) / sizeof(arr[0]); //6 //qsort(arr, sz-1, sizeof(arr[0]), cmp_float); //因為sizeof把/0也算進去了,所以計算出來的值比字符串本身長度多1 int sz = strlen(arr); //5 qsort(arr, sz, sizeof(arr[0]), cmp_char); printf("%s/n",arr);}
先看看下面這段程序有沒有問題?
int cmp_chars(const void* e1, const void* e2){ return strcmp((char*)e1, *(char*)e2);}void test2(){ char* arr1 = "abc"; char* arr2 = "wcad"; char* arr3 = "cab"; char* p[3] = { arr1,arr2,arr3 }; int sz = sizeof(p) / sizeof(p[0]); qsort(p, sz, sizeof(p[0]), cmp_chars); int i = 0; for (i = 0; i < sz; i++) { printf("%s/n", p[i]); }}
?打印出來發(fā)現(xiàn):結果是錯誤的!
?->調(diào)試后發(fā)現(xiàn):e2存放的是p的地址(char**類型),e1存放的是p指向的下一個元素的地址(char**類型)????????
對于這種寫法,傳進去的是p的地址,strcmp()會將p地址對應的內(nèi)容轉(zhuǎn)化成字符串,也就是將p中arr1,arr2,arr3的地址轉(zhuǎn)化成字符串
實際上應該傳p地址空間中arr1,arr2的地址,這樣strcmp()才能找到arr1和arr2對應的字符串,因此得先把e1,e2轉(zhuǎn)化成char**,這樣解引用以后才是一個char*的地址
原因:把p傳給qsort,p是數(shù)組名->首元素地址,元素類型為char*>,所以p的類型為:char**類型。? 所以e1 和e2也要強制類型轉(zhuǎn)化為char**,解引用e1,e2才是對應字符串的地址!
正解:?
int cmp_chars(const void* e1, const void* e2){ return strcmp(*(char**)e1, *(char**)e2);}void test2(){ char* arr1 = "abc"; char* arr2 = "wcad"; char* arr3 = "cab"; char* p[3] = { arr1,arr2,arr3 }; int sz = sizeof(p) / sizeof(p[0]); qsort(p, sz, sizeof(p[0]), cmp_chars); int i = 0; for (i = 0; i < sz; i++) { printf("%s/n", p[i]); }
比較年齡->實際比較的是整形
比較名字->實際比較的是字符串->使用strcmp函數(shù),不能使用 == 判斷
struct Stu{ int age; char name[20];};//比較結構體中元素的年齡int cmp_age(const void* e1, const void* e2){ //本質(zhì)是比較整形 return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;}//比較名字int cmp_name(const void* e1, const void* e2){ //本質(zhì)是字符串比較->使用strcmp函數(shù) return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);}void test2(){ //創(chuàng)建結構體數(shù)組,用大括號初始化 struct Stu s[3] = { {19,"Mango"},{18,"Lemon"},{20,"Hello"} }; int sz = sizeof(s) / sizeof(s[0]); //以年齡排 qsort(s, sz, sizeof(s[0]), cmp_age); printf("%s %d ",s[0].name,s[0].age); printf("%s %d ", s[1].name, s[1].age); printf("%s %d ", s[2].name, s[2].age); printf("/n"); //以姓名排 qsort(s, sz, sizeof(s[0]), cmp_name); printf("%s %d ", s[0].name, s[0].age); printf("%s %d ", s[1].name, s[1].age); printf("%s %d ", s[2].name, s[2].age); printf("/n");}
注意:比較函數(shù)中,返回類型是int,最后相減的值要強制類型轉(zhuǎn)化為int ,但這也會造成錯誤,建議使用方法2.
//寫法1:可能會出錯// 原因: 0.2 -0.1 = 0.1 強制類型轉(zhuǎn)化為int后 結果為0//int cmp_float(const void* e1, const void* e2)//{// //返回類型是int 所以相減后的結果要強制類型轉(zhuǎn)化// return (int)(*(float*)e1 - *(float*)e2);//}//寫法2:對應上qsort的返回值int cmp_float(const void* e1, const void* e2){ if ((*(float*)e1 - *(float*)e2) > 0.00000) return 1; else if ((*(float*)e1 - *(float*)e2) == 0.000000) return 0; else return -1;}void test3(){ float arr[5] = { 5.01f,5.01f,0.02f,0.01f,5.001f }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp_float); int i = 0; for (i = 0; i < sz; i++) { printf("%f ", arr[i]); }}
主要思想:相鄰的兩個元素進行比較?
?
?對于冒泡排序:?n個元素 共進行n-1趟冒泡排序。一趟可以使一個元素在特定位置上,每趟排序可以少比較一個元素
但是冒泡排序只能排序整形
void BubbleSort(int* arr, int sz){ int i = 0; int j = 0; int flag = 1;//假設一開始有序 //共進行sz-1趟 for (i = 0; i < sz-1; i++) { // 每一趟 for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 0; } } if (flag == 1) { break; } }}int main(){ int arr[10] = { 2,3,6,7,9,0,0,3,2,10 }; int sz = sizeof(arr) / sizeof(arr[0]); BubbleSort(arr, sz); return 0;}
qsort庫函數(shù)使用的是什么參數(shù),我們設計的函數(shù)就使用什么參數(shù)!
??
1.為何將base強制類型轉(zhuǎn)化為char*型指針:
原因:char* 指針+1跳過一個字節(jié),+width:跳過width個字節(jié),指向下一個元素。轉(zhuǎn)化為其他類型不合適
2.?交換函數(shù):還要把寬度(每個元素所占字節(jié)數(shù))傳過去
因為交換的時候是傳地址,所以要知道元素的寬度,一個字節(jié)一個字節(jié)的交換 ,這樣也證明了使用char*指針的好處!
3.(char*)base + j * width, (char*)base + (j + 1) * width,
? 當j = 0時:比較的是第一個元素和第二個元素
? ?j = 1時,比較的是第二個元素和第三個元素
? ? .... ?很妙的寫法
//交換 --一個字節(jié)一個字節(jié)的交換,共交換width次void Swap(char* buf1, char* buf2, size_t width){ size_t i = 0; for (i = 0; i < width; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; }}void my_BubbleSort(void* base, size_t num,size_t width, int(*cmp)(const void* e1, const void* e2)){ //冒泡排序 //若要排序n個元素,只需要進行n-1趟 //每一趟可以少比較一個元素,每一趟可以使一個元素在確定的位置上 //num:要排序元素的個數(shù) 類型是size_t //num是無符號數(shù) 防止產(chǎn)生警告 所以i和j也定義為size_t // size_t == unsigned int size_t i = 0; size_t j = 0; //共進行num-1趟 for (i = 0; i < num; i++) { //每一趟 for (j = 0; j < num - 1 - i; j++) { //比較 //傳地址 //相鄰兩個元素比較 width:寬度,每個元素所占字節(jié) //排成升序 if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0) { //交換兩數(shù) Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width ); } } }}
當然 ,交換也可以使用庫函數(shù)memcpy
dest:目標空間?
?src:要拷貝到目標空間的字符 -因為不作修改,所以可以用const修飾
count:字節(jié)數(shù)
char tmp [30]; //防止結構體類型之類的類型 臨時空間memcpy(tmp, (char*)base + j * size, size); memcpy( (char*)base + j * size, (char*)base + (j + 1) * size, size);memcpy( (char*)base + (j + 1) * size, tmp, size);
?如果文章對你有幫助的,歡迎大佬們點個贊留言呀!如果有錯誤的話,請評論告知!
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/118799.html
摘要:參數(shù)含義上圖是函數(shù)各個參數(shù)的含義,讓我們一個個來看。使用方式頭文件要使用函數(shù)我們首先需要引用一個頭文件的實現(xiàn)函數(shù)給函數(shù)規(guī)定了特定的參數(shù)。因此我們設計函數(shù)時要嚴格遵守其參數(shù)設定。 目錄 1.參數(shù)含義 1.首元素地址base 2.元素個數(shù)num 3.元素大小size 4.自定義比較函數(shù)compa...
摘要:函數(shù)詳解函數(shù)原型函數(shù)的作用及用法函數(shù)的參數(shù)函數(shù)實例排序一個整型數(shù)組排序一個結構體用冒泡排序模擬一個函數(shù)函數(shù)原型函數(shù)的作用及用法函數(shù)的功能是對數(shù)組進行排序,數(shù)組有個元素,每個元素大小為可以排序數(shù)字,字符,結構體等多種類型 ...
摘要:我們以冒泡排序為例,模擬實現(xiàn)函數(shù)。交換每單位字節(jié)對于的二進制序列這樣,冒泡排序就能排序多種數(shù)據(jù)類型,模擬實現(xiàn)了函數(shù),當然也可以使用其他的排序方法模擬實現(xiàn)函數(shù)。 ??...
摘要:故使用無具體類型,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算解引用,整數(shù)等。求指針所占字節(jié)而不是解引用訪問權限大小。數(shù)組就是整個數(shù)組的大小,數(shù)組元素則是數(shù)組元素的大小,指針大小都為。 ...
摘要:指針的大小是固定的個字節(jié)位平臺位平臺。二指針數(shù)組指針數(shù)組是一個存放指針的數(shù)組。是一個數(shù)組指針,該指針指向的數(shù)組有個元素,每個元素都是的。錯誤錯誤二維數(shù)組首元素指的是第一行。 ...
閱讀 3774·2021-11-11 11:02
閱讀 3504·2021-10-11 10:57
閱讀 3615·2021-09-22 16:00
閱讀 1853·2021-09-02 15:15
閱讀 1336·2019-08-30 15:56
閱讀 1015·2019-08-30 15:54
閱讀 2738·2019-08-30 12:43
閱讀 3546·2019-08-29 16:06