嵌入式算法之排序算法
1、冒泡排序
冒泡排序(bubble sort)是一種C語(yǔ)言入門(mén)級(jí)的簡(jiǎn)單排序算法,重復(fù)地走訪過(guò)要排序的元素列,依次比較兩個(gè)相鄰的元素,如果順序錯(cuò)誤進(jìn)行交換。重復(fù)地檢查對(duì)比直到?jīng)]有相鄰元素需要交換,也就是說(shuō)該元素列已經(jīng)排序完成。算法的名字由來(lái)是因?yàn)樵叫?大)的元素會(huì)經(jīng)由交換慢慢“浮”到數(shù)列的頂端(升序或降序排列),就如同水中的氣泡最終會(huì)上浮到頂端一樣,故名“冒泡排序”。
算法描述
1、比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就進(jìn)行交換
2、對(duì)每一對(duì)相鄰元素作同樣操作,從開(kāi)始第一對(duì)到結(jié)尾的最后一對(duì),這樣在最后的元素應(yīng)該會(huì)是最大的數(shù)
3、針對(duì)所有的元素重復(fù)以上的步驟,除了最后一個(gè)
4、重復(fù)步驟1~3,直到排序完成
源碼
- #include <stdio.h>
 - #define ARRAY_SIZE 15
 - void log(char *head, int *data, int len)
 - {
 - unsigned char i;
 - printf("%s:", head);
 - for(i = 0; i < len; i++)
 - {
 - printf("%02d ", data[i]);
 - }
 - printf("\r\n");
 - }
 - //從小到大排序
 - void bubble_sort(int *data, int size)
 - {
 - int i, j, temp;
 - for(i = 0; i < size; i++)
 - {
 - for(j = 0; j < size-i-1; j++)
 - {
 - if(data[j] > data[j + 1]) // 相鄰元素兩兩對(duì)比
 - {
 - temp = data[j + 1]; // 元素交換
 - data[j + 1] = data[j];
 - data[j] = temp;
 - }
 - }
 - }
 - }
 - int main(void)
 - {
 - int data[ARRAY_SIZE] = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
 - log("source", data, ARRAY_SIZE);
 - bubble_sort(data, ARRAY_SIZE);
 - log("sort ", data, ARRAY_SIZE);
 - return 0;
 - }
 
運(yùn)行結(jié)果
- source:03 44 38 05 47 15 36 26 27 02 46 04 19 50 48
 - sort :02 03 04 05 15 19 26 27 36 38 44 46 47 48 50
 
2、選擇排序
選擇排序(selection sort)是一種簡(jiǎn)單直觀的排序算法,首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再?gòu)氖S辔磁判蛟刂欣^續(xù)尋找最小(大)元素,然后放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
算法描述
1、初始狀態(tài),數(shù)據(jù)都屬于無(wú)序區(qū),有序區(qū)為空
2、從無(wú)序區(qū)中選出最小元素,將它與無(wú)序區(qū)的第1個(gè)元素交換
3、再?gòu)臒o(wú)序區(qū)的下個(gè)元素重復(fù)第2步,直至無(wú)序區(qū)為空
源碼
- void selection_sort(int *data, int size)
 - {
 - int i, j, temp;
 - int min;
 - for(i = 0; i < size - 1; i++)
 - {
 - min = i;
 - for(j = i + 1; j < size; j++)
 - {
 - if(data[j] < data[min]) // 尋找最小的數(shù)
 - {
 - min = j; // 將最小數(shù)的索引保存
 - }
 - }
 - if(min != i) // 需要交互
 - {
 - temp = data[i];
 - data[i] = data[min];
 - data[min] = temp;
 - }
 - }
 - }
 
前面算法的bubble_sort范例替換為selection_sort即可,運(yùn)行結(jié)果一致
3、插入排序
插入排序(insertion sort)的算法,工作原理是通過(guò)構(gòu)建有序序列,對(duì)于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入。
算法描述
1、從第一個(gè)元素開(kāi)始,該元素可認(rèn)為已排序
2、取出下一個(gè)元素,在已經(jīng)排序的元素序列中從后向前掃描
3、如果該元素(已排序)大于新元素,將該元素移到下一位置
4、重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置,將新元素插入到該位置后
5、重復(fù)步驟2~4
源碼
- void insertion_sort(int *data, int size)
 - {
 - int i, pre, current;
 - for(i = 1; i < size; i++)
 - {
 - pre = i - 1;
 - current = data[i];
 - while(pre >= 0 && data[pre] > current) //當(dāng)前元素與的有序區(qū)逐個(gè)比較再插入
 - {
 - data[pre + 1] = data[pre];
 - pre--;
 - }
 - data[pre + 1] = current;
 - }
 - }
 
4、標(biāo)準(zhǔn)庫(kù)函數(shù)qsort
前面三種排序算法都只是針對(duì)單個(gè)元素進(jìn)行排序,但實(shí)際應(yīng)用中,基于某個(gè)數(shù)值對(duì)一個(gè)大結(jié)構(gòu)體進(jìn)行排序,比如wifi信息結(jié)構(gòu)體數(shù)組,包括其mac、名稱、加密信息、和信號(hào)強(qiáng)度,依據(jù)信息強(qiáng)度對(duì)wifi信息進(jìn)行排序,每次數(shù)據(jù)交換意味著兩次內(nèi)存拷貝,這種場(chǎng)景下采用選擇排序略優(yōu)。
相比于自己造輪子,C語(yǔ)言標(biāo)準(zhǔn)庫(kù)函數(shù)也許更合適;qsort函數(shù)是C語(yǔ)言自帶的排序函數(shù),包含在
函數(shù)原型
- void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
 
base - 指針,數(shù)組的第一個(gè)元素進(jìn)行排序
nitems - 數(shù)組中的元素?cái)?shù)目
size - 數(shù)組中的每個(gè)元素的大小(以字節(jié)為單位)
compar - 基于這個(gè)函數(shù)比較兩個(gè)元素
返回:值不返回任何值
缺點(diǎn):對(duì)于有多個(gè)重復(fù)值的數(shù)組來(lái)說(shuō),效率較低不穩(wěn)定
范例
- //qsort要結(jié)合compare使用
 - int compare(const void *value1, const void *value2)
 - {
 - //升序或降序在此調(diào)整
 - return (*(int*)value1 - *(int*)value2);
 - }
 - int main(void)
 - {
 - int data[ARRAY_SIZE] = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
 - log("source", data, ARRAY_SIZE);
 - qsort(data, ARRAY_SIZE, sizeof(int), compare);
 - log("sort ", data, ARRAY_SIZE);
 - return 0;
 - }
 
其效果和前面三種算法一樣,而且可擴(kuò)展針對(duì)結(jié)構(gòu)體內(nèi)某個(gè)元素值對(duì)整體排序,滿足前面的wifi信息按信號(hào)強(qiáng)度排序的需求。
- #include <stdio.h>
 - #define WIFI_AP_MAX 5
 - typedef unsigned char uint8_t;
 - typedef signed char int8_t;
 - typedef unsigned short uint16_t;
 - typedef signed short int16_t;
 - typedef unsigned int uint32_t;
 - typedef struct
 - {
 - uint32_t bssid_low; // mac address low
 - uint16_t bssid_high; // mac address high
 - uint8_t channel; // channel id
 - int8_t rssi; // signal strength <sort>
 - } wifiApInfo_t;
 - //qsort要結(jié)合compare使用,按信號(hào)強(qiáng)度rssi升序排列
 - int compare(const void *value1, const void *value2)
 - {
 - const wifiApInfo_t *ctx1 = (const wifiApInfo_t *)value1;
 - const wifiApInfo_t *ctx2 = (const wifiApInfo_t *)value2;
 - return (ctx1->rssi - ctx2->rssi);
 - }
 - static wifiApInfo_t wifiApInfo[WIFI_AP_MAX] =
 - {
 - {0x5555, 0x55, 5, -55},
 - {0x1111, 0x11, 1, -51},
 - {0x3333, 0x33, 3, -53},
 - {0x4444, 0x44, 4, -54},
 - {0x2222, 0x22, 2, -52},
 - };
 - void wifi_log(char *head, void *data, int size)
 - {
 - unsigned char i;
 - const wifiApInfo_t *wifi = (wifiApInfo_t *)data;
 - printf("%s:\r\n", head);
 - for(i = 0; i < size; i++)
 - {
 - printf("%X %X %d [%d] \r\n", wifi[i].bssid_low, wifi[i].bssid_high, wifi[i].channel, wifi[i].rssi);
 - }
 - printf("\r\n\r\n");
 - }
 - int main(void)
 - {
 - wifi_log("source", wifiApInfo, WIFI_AP_MAX);
 - qsort(wifiApInfo, WIFI_AP_MAX, sizeof(wifiApInfo_t), compare);
 - wifi_log("sort", wifiApInfo, WIFI_AP_MAX);
 - return 0;
 - }
 
運(yùn)行結(jié)果
- source:
 - 5555 55 5 [-55]
 - 1111 11 1 [-51]
 - 3333 33 3 [-53]
 - 4444 44 4 [-54]
 - 2222 22 2 [-52]
 - //依據(jù)信號(hào)強(qiáng)度關(guān)鍵字,對(duì)wifi信息整體數(shù)據(jù)同步進(jìn)行了排序
 - sort:
 - 5555 55 5 [-55]
 - 4444 44 4 [-54]
 - 3333 33 3 [-53]
 - 2222 22 2 [-52]
 - 1111 11 1 [-51]
 
5、總結(jié)
沒(méi)有最好的排序算法,選擇哪種方式需要結(jié)合待排序數(shù)據(jù)量的大小和類型,以前原始數(shù)據(jù)是否大概有序,選擇合適的算法滿足需求即可。


















 
 
 






 
 
 
 