一、冒泡排序簡述
1、概念
冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。
它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端。
2、實例分析
以數組為例進行說明:
數組a[4] = {4,3,2,1}
從前向后依次比較兩個元素的大小,如果順序錯誤就交換它們。經過這樣一輪,最大的元素就被交換到了數組的頂端,好像是最大的元素“浮”上去一樣。經過這樣一輪,最后的一個元素的已經確定。a[4] = {3,2,1,4}
再次重復上邊的操作,只不過因為上一輪最后一個元素已經確定,所以這一次比較的終點(以此為界,不能超過此界)就是上一輪的最后一個元素。也就是,第二輪的比較中,數組最后一個元素沒有參與比較。第二輪比較中的最后一個元素是倒數第二個元素。經過這樣一輪比較,倒數第二個元素也被確定。a[4] = {2,1,3,4}
重復這樣的操作,直到數組的第二個元素被確定。因為除了第一個元素外,所有的元素都被鎖定,所以第一個元素實際上也被確定。到此為止,排序完成。a[4] = {1,2,3,4}
3、冒泡排序的關鍵
<1> 每經過一輪的排序,一個最大的元素被“浮”到對應的位置。隨之,下一次比較的終點也需要向前移一個元素。
<2> 當正數第二個元素被確定的時候,冒泡排序完成。
二、冒泡法應用於單向鏈表排序
1、實例展示
① 初始鏈表
② 第一輪排序
③ 第二輪排序
④ 第三輪排序
2、算法流程圖
3、源碼以及測試
1 #include <stdio.h> 2 #include <malloc.h> 3 4 /* 排序狀態取值表 */ 5 typedef enum 6 { 7 SORT_OK, /* 排序成功標志 */ 8 SORT_ERR /* 排序失敗標志 */ 9 }SORTSTATE; 10 11 /* 接點結構體 */ 12 struct node{ 13 struct node * pnext; 14 unsigned int value; 15 }; 16 17 typedef struct node Node; 18 19 SORTSTATE sort(Node * * chainhead); 20 21 /** @函數功能:測試單向鏈表排序功能 22 * @輸入參數:無 23 * @輸出參數:無用 24 */ 25 int main(void) 26 { 27 Node * head,* p; 28 SORTSTATE status; 29 30 /* 構建單向鏈表 */ 31 p = (Node *)malloc(sizeof(Node)); 32 head = p; /* 保存鏈表頭部 */ 33 p->value = 5; 34 p->pnext = (Node *)malloc(sizeof(Node)); 35 36 p = p->pnext; 37 p->value = 97; 38 p->pnext = (Node *)malloc(sizeof(Node)); 39 40 p = p->pnext; 41 p->value = 7; 42 p->pnext = (Node *)malloc(sizeof(Node)); 43 44 p = p->pnext; 45 p->value = 65; 46 p->pnext = (Node *)malloc(sizeof(Node)); 47 48 p = p->pnext; 49 p->value = 12; 50 p->pnext = (Node *)malloc(sizeof(Node)); 51 52 p = p->pnext; 53 p->value = 1; 54 p->pnext = NULL; /* 鏈尾初始化為空 */ 55 56 /* 打印鏈表的內容 */ 57 p = head; 58 while(p != NULL){ 59 printf("%4d",p->value); 60 p = p->pnext; 61 } 62 printf("\n"); 63 64 /* 鏈表排序 */ 65 status = sort(&head); 66 if(status == SORT_ERR){ 67 printf("Chain is wrong!\n"); 68 } 69 70 /* 打印鏈表的內容 */ 71 p = head; 72 while(p != NULL){ 73 printf("%4d",p->value); 74 p = p->pnext; 75 } 76 printf("\n"); 77 78 return 0; 79 } 80 81 82 /** @函數功能:單向鏈表排序 83 * @輸入參數:指向鏈表頭部的指針 84 * 注意:指向指針的指針可以修改指針的指向 85 * @輸出參數:SORTSTATE 排序成功與否狀態 86 */ 87 SORTSTATE sort(Node * * chainhead) 88 { 89 Node * head, /* 當前比較接點的上一個接點 */ 90 * first, /* 當前比較接點 */ 91 * second, /* 當前參與比較的另一個接點 */ 92 * end; /* 當前比較接點的終點 93 * 終點意味着從終點開始往后的 94 * 鏈表排序已經確定,只需要將 95 * 終點前的所有接點按照冒泡法 96 * 排序,排序就將完成。 97 */ 98 99 if(*chainhead == NULL) /* 鏈表是否為空 */ 100 return SORT_ERR; 101 if((*chainhead)->pnext == NULL) /* 鏈表是否就只有一個接點 */ 102 return SORT_OK; 103 104 end = NULL; /* 第一輪冒泡排序的終點接點值為NULL */ 105 106 /* 冒泡法排序,可能有很多輪次 */ 107 while(end != (*chainhead)->pnext){ /* 如果排序的終點等於接點的第二個地址, 108 * 也就是說從第二個接點開始所有的接點 109 * 都已經按照從小到大的順序確定了位置。 110 * 顯然,剩下的唯一一個“第一接點”位置 111 * 也就確定了。所有排序全部完成。 112 */ 113 114 /* 首先比較位於頭部的兩個接點,由於位於頭部, 115 * 與其他接點不一樣,需要放在循環外邊,單獨處理。 116 */ 117 first = *chainhead; /* 第一個比較接點是鏈表頭部指向的接點 */ 118 second = first->pnext; /* 第二個比較接點是緊鄰的第二個接點 */ 119 120 /* 是否需要更改鏈表的連接順序 */ 121 if(first->value > second->value){ 122 *chainhead = second; /* 更改鏈表頭部的指向 */ 123 /* 重新連接鏈表,就相當於對鏈表排序 */ 124 first->pnext = second->pnext; 125 second->pnext = first; 126 } 127 128 /* 移動比較接點到下兩個接點 */ 129 head = *chainhead; /* 當前比較接點的上一個接點則是頭部接點 */ 130 first = head->pnext; /* 當前比較接點 */ 131 second = first->pnext; /* 當前參與比較的另一個接點 */ 132 133 while(second != end) /* 此輪的比較是否結束 */ 134 { 135 /* 是否需要更改鏈表的連接順序 */ 136 if(first->value > second->value){ 137 /* 重新連接鏈表,就相當於對鏈表排序 */ 138 head->pnext = second; 139 first->pnext = second->pnext; 140 second->pnext = first; 141 142 } 143 /* 移動比較接點到下兩個接點 */ 144 head = head->pnext; 145 first = head->pnext; 146 second = first->pnext; 147 } 148 149 end = first; /* 一輪排序完成,結束接點位置上移一個 */ 150 } 151 152 return SORT_OK; /* 排序成功 */