中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言中如何使用qsort函數

發布時間:2021-09-02 13:47:21 來源:億速云 閱讀:150 作者:小新 欄目:開發技術

小編給大家分享一下C語言中如何使用qsort函數,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

    一.qsort函數是什么

    我們可以使用  搜索庫函數網址或者MSDN軟件進行查找。

    qsort()函數:快速排序的函數  -引用stdlib.h頭文件

    C語言中如何使用qsort函數

    參數說明:

    void qsort ( 
    
        void* base, //要排序的目標數組
        size_t num,     //待排序的元素個數
        size_t width,    //一個元素的大小,單位是字節
        int(*cmp)(const void* e1, const void* e2)
    
    );

    其中cmp是函數指針,cmp指向的是:排序時,用來比較兩個元素的函數。需要自己編寫。

    返回值:

    C語言中如何使用qsort函數

     二.使用qsort排序-以升序為例

    關于void*型指針:

      void*:無具體類型的指針   能夠接收任意類型的地址
     缺點:不能進行運算。不能+-整數,不能解引用

    int a  = 0;
    float f = 5.5f;
    void* p1 = &a;
    void* p2 = &f;
    p1 = p1+1;    //err

    1.整形數組排序

    注意:

    1.比較函數的參數類型為void* ,我們要進行強制類型轉換!且要解引用才能得到對應的值! 

    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* 所以要強制類型轉化,還要解引用才是對應的值!!!
    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);
    }

    2.字符數組排序

    注意使用sizeof()操作符和strlen()函數的區別

    //注意要要強制類型轉換!! 要解引用!!!  本質上是比較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);
    }

    3.字符指針數組排序

    先看看下面這段程序有沒有問題?

    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]);
    	}
    }

    打印出來發現:結果是錯誤的!

    C語言中如何使用qsort函數

     ->調試后發現:e2存放的是p的地址(char**類型),e1存放的是p指向的下一個元素的地址(char**類型)        

    對于這種寫法,傳進去的是p的地址,strcmp()會將p地址對應的內容轉化成字符串,也就是將p中arr1,arr2,arr3的地址轉化成字符串

    實際上應該傳p地址空間中arr1,arr2的地址,這樣strcmp()才能找到arr1和arr2對應的字符串,因此得先把e1,e2轉化成char**,這樣解引用以后才是一個char*的地址

    原因:把p傳給qsort,p是數組名->首元素地址,元素類型為char*>,所以p的類型為:char**類型。  所以e1 和e2也要強制類型轉化為char**,解引用e1,e2才是對應字符串的地址!

    C語言中如何使用qsort函數

    正解: 

    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]);
    	}

    4.結構體數組排序

    比較年齡->實際比較的是整形

    比較名字->實際比較的是字符串->使用strcmp函數,不能使用 == 判斷

    struct Stu
    {
    	int age;
    	char name[20];
    };
    //比較結構體中元素的年齡
    int cmp_age(const void* e1, const void* e2)
    {
    	//本質是比較整形
    	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
    }
    //比較名字
    int cmp_name(const void* e1, const void* e2)
    {
    	//本質是字符串比較->使用strcmp函數
    	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
    }
    void test2()
    {
    	//創建結構體數組,用大括號初始化
    	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");
    }

    5.浮點型數組排序

    注意:比較函數中,返回類型是int,最后相減的值要強制類型轉化為int ,但這也會造成錯誤,建議使用方法2.

    //寫法1:可能會出錯
    // 原因: 0.2 -0.1 = 0.1 強制類型轉化為int后 結果為0
    //int cmp_float(const void* e1, const void* e2)
    //{
    //	//返回類型是int  所以相減后的結果要強制類型轉化
    //	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]);
    	}
    }

    三.使用冒泡排序思想模擬實現qsort函數

     1.什么是冒泡排序:

    C語言中如何使用qsort函數

    主要思想:相鄰的兩個元素進行比較 

     C語言中如何使用qsort函數

     對于冒泡排序: n個元素 共進行n-1趟冒泡排序。一趟可以使一個元素在特定位置上,每趟排序可以少比較一個元素

    但是冒泡排序只能排序整形

     2.冒泡排序代碼

    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;
    }

    3. 使用冒泡排序思想模擬實現qsort函數

    qsort庫函數使用的是什么參數,我們設計的函數就使用什么參數!

    C語言中如何使用qsort函數  

    1.為何將base強制類型轉化為char*型指針:

    原因:char* 指針+1跳過一個字節,+width:跳過width個字節,指向下一個元素。轉化為其他類型不合適

    2. 交換函數:還要把寬度(每個元素所占字節數)傳過去
    因為交換的時候是傳地址,所以要知道元素的寬度,一個字節一個字節的交換 ,這樣也證明了使用char*指針的好處!

    3.(char*)base + j * width, (char*)base + (j + 1) * width,

      當j = 0時:比較的是第一個元素和第二個元素
       j = 1時,比較的是第二個元素和第三個元素
        ....  很妙的寫法

    //交換 --一個字節一個字節的交換,共交換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:要排序元素的個數 類型是size_t 
        //num是無符號數 防止產生警告 所以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:寬度,每個元素所占字節
    			//排成升序
    			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
    			{
    				//交換兩數
    				Swap( (char*)base + j * width, (char*)base + (j + 1) * width, width );
    			}
    		}
    	}
    }

    當然 ,交換也可以使用庫函數memcpy

    C語言中如何使用qsort函數

    dest:目標空間 

     src:要拷貝到目標空間的字符 -因為不作修改,所以可以用const修飾

    count:字節數

    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);

    以上是“C語言中如何使用qsort函數”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    理塘县| 格尔木市| 托克逊县| 东明县| 枣强县| 锡林浩特市| 乳源| 墨竹工卡县| 通州市| 凤翔县| 上虞市| 凤庆县| 黑龙江省| 南木林县| 呼伦贝尔市| 新和县| 上林县| 田林县| 黔西县| 鄯善县| 康马县| 凉城县| 健康| 洛浦县| 海安县| 报价| 晴隆县| 芜湖县| 文水县| 应用必备| 德江县| 麻栗坡县| 胶州市| 巩留县| 萍乡市| 濉溪县| 确山县| 西吉县| 定边县| 泸西县| 芦山县|