冒泡排序

【1】冒泡排序理论

(1)基本概念

由于在排序过程中一般是小数往前放,大数往后放,相当于气泡往上升过程,所以称作冒泡排序。

如下图(鱼冒泡):

冒泡排序的时间复杂度为O(n*n)。

冒泡排序具有稳定性(参见随笔《常用排序算法稳定性分析》)。

(2)逻辑分析

依次比较相邻的两个数,将小数换到前面,大数换在后面。

第一趟,过程如下概述:

首先,比较第1个和第2个数,将小数换前,大数换后。

然后,比较第2个数和第3个数,将小数换前,大数换后。

如此继续,比较第n个数和第(n + 1)个数,将小数换前,大数换后。

直至比较最后两个数,将小数换前,大数换后。

至此,第一趟结束,将最大的数换到了最末位。

第二趟:仍从第一对数开始比较(因为可能由于第一趟时第2个数和第3个数的交换后,使得第1个数不再小于第2个数),将小数换前,大数换后。

一直比较到倒数第二个数(倒数第一的位置上已经是最大的)。第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。

如此下去,重复以上过程,直至最终完成排序。

【2】何谓排序算法稳定性?

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些相同关键字记录的相对次序保持不变。

即在原序列中,Ri == Rj,且Ri在Rj之前,而在排序后的序列中,Ri仍在Rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

【3】冒泡排序图解

【4】C++实现冒泡排序

(1)简单实现。示例代码如下:

  1 #include <iostream>
  2 using namespace std;
  3  
  4 #define SWAP(x, y) { int t; t = x; x = y; y = t; }
  5 #define SIZE 5
  6  
  7 void InitArray(int br[])
  8 {
  9     for (int i = 0; i < SIZE; ++i)
 10     {
 11         br[i] = (rand() + 10) % 100;
 12     }
 13 }
 14  
 15 void PrintArr(int ar[])
 16 {
 17     for (int i = 0; i < SIZE; ++i)
 18     {
 19         cout << ar[i] << "   ";
 20     }
 21     cout << endl;
 22 }
 23 
 24 void bubble_sort(int ar[], int n)  
 25 {  
 26     if (NULL == ar || 0 == n)
 27     {
 28         return;
 29     }
 30 
 31     for (int i = 0; i < n; ++i)  
 32     {  
 33         for (int j = 0; j < n - i; ++j)  
 34         {  
 35             if (ar[j] > ar[j + 1]) 
 36             {
 37                 SWAP(ar[j], ar[j + 1]);
 38             }
 39         }   
 40     }  
 41 }  
 42 
 43 void Test_Bubble_Sort(int ar[], int n) 
 44 {  
 45     if (NULL == ar || 0 == n)
 46     {
 47         return;
 48     }
 49 
 50     for (int i = 0; i < n; ++i)  
 51     {
 52         cout << "i==" << i << " " << endl;
 53         for (int j = 0; j < n - i; ++j)  
 54         {
 55             cout << "  " << "j==" << j << " << ";
 56             if (ar[j] > ar[j + 1]) 
 57             {
 58                 SWAP(ar[j], ar[j + 1]);
 59             }
 60             PrintArr(ar);
 61         }
 62     }  
 63 }
 64 
 65 void  main()
 66 {
 67     int ar[SIZE];
 68     InitArray(ar);
 69     cout << "排序前数据:" << endl;
 70     PrintArr(ar);
 71     cout << endl << "测试排序过程数据:" << endl;
 72     Test_Bubble_Sort(ar, SIZE - 1);
 73     cout << endl << "排序后数据:" << endl;
 74     PrintArr(ar);
 75 
 76     system("pause");
 77 }
 78 
 79 // run out:
 80 /*
 81 排序前数据:
 82 51   77   44   10   79
 83 
 84 测试排序过程数据:
 85 i==0
 86   j==0 << 51   77   44   10   79
 87   j==1 << 51   44   77   10   79
 88   j==2 << 51   44   10   77   79
 89   j==3 << 51   44   10   77   79
 90 i==1
 91   j==0 << 44   51   10   77   79
 92   j==1 << 44   10   51   77   79
 93   j==2 << 44   10   51   77   79
 94 i==2
 95   j==0 << 10   44   51   77   79
 96   j==1 << 10   44   51   77   79
 97 i==3
 98   j==0 << 10   44   51   77   79
 99 
100 排序后数据:
101 10   44   51   77   79
102 请按任意键继续. . .
103 */

 (2)双向冒泡排序

单向冒泡排序每次前后两项记录作比较,小者换前,大者置后。

而双向冒泡排序实现即是一次正向冒泡,从左至右。然后一次反向冒泡,从右至左。

所谓正向是把最大的记录放到表尾,所谓反向是将最小记录放到表头,如此反复。

changeFlag 用来标志是否有交换,如果没有交换则终止循环(避免无意义的再比较)。

示例代码如下:

  1 #include <iostream>
  2 using namespace std;
  3  
  4 #define MAXSIZE 12
  5 #define SWAP(x, y)    { int t; t = x; x = y; y = t; }
  6  
  7 void InitArray(int br[])
  8 {
  9     for (int i = 0; i < MAXSIZE; ++i)
 10     {
 11         br[i] = (rand() + 10) % 100;
 12     }
 13 }
 14 
 15  void ShowArray (int br[])
 16  {
 17      for (int i = 0; i < MAXSIZE; ++i)
 18      {
 19          cout << br[i] << "  ";
 20      }
 21      cout << endl;
 22  }
 23 
 24  void Double_Bubble_Sort(int br[], int n)
 25  {
 26      if (NULL == br || 0 == n)
 27      {
 28          return;
 29      }
 30 
 31      bool flag = false;
 32      for (int i = 0; i < n; ++i)
 33      {
 34          flag = false;
 35          for (int j = 0; j < n - i; ++j)
 36          {
 37              if (br[j] > br[j + 1])
 38              { // 最大的向后移动
 39                  SWAP(br[j], br[j + 1]);
 40                  flag = true;
 41              }
 42          }
 43          if (!flag) 
 44              break;
 45 
 46          for (int j = n-i-1; j > i; --j)
 47          {
 48              if (br[j] < br[j - 1])
 49              { // 最小的向前移动
 50                  SWAP(br[j], br[j - 1]);
 51                  flag = true;
 52              }
 53          }
 54          if (!flag) 
 55              break;
 56      }
 57  }
 58 
 59  void Test_Double_Bubble_Sort(int br[], int n)
 60  {
 61      if (NULL == br || 0 == n)
 62      {
 63          return;
 64      }
 65 
 66      bool flag = false;
 67      for (int i = 0; i < n; ++i)
 68      {
 69          cout << endl << "" << i+1 << "次循环前:" << endl;
 70          ShowArray(br);
 71          flag = false;
 72          for (int j = 0; j < n - i; ++j)
 73          {
 74              if (br[j] > br[j + 1])
 75              { // 最大的向后交换
 76                  SWAP(br[j], br[j + 1]);
 77                  flag = true;
 78              }
 79          }
 80          cout << "" << i+1 << "次正向循环后:" << endl;
 81          ShowArray(br);
 82          if (!flag) 
 83              break;
 84 
 85          for (int j = n-i-1; j > i; --j)
 86          {
 87              if (br[j] < br[j - 1])
 88              { // 最小的向前交换
 89                  SWAP(br[j], br[j - 1]);
 90                  flag = true;
 91              }
 92          }
 93          cout << "" << i+1 << "次反向循环后:" << endl;
 94          ShowArray(br);
 95          if (!flag) 
 96              break;
 97      }
 98  }
 99  void main()
100  {
101      int ar[MAXSIZE];
102      InitArray(ar);
103      cout << "源数据:" << endl;
104      ShowArray(ar);
105      Test_Double_Bubble_Sort(ar, MAXSIZE - 1);
106      cout << endl << "完成排序后:" << endl;
107      ShowArray(ar);
108 
109      system("pause");
110  }
111 
112 // run out:
113 /*
114 源数据:
115 51  77  44  10  79  34  88  68  72  74  15  55
116 
117 第1次循环前:
118 51  77  44  10  79  34  88  68  72  74  15  55
119 第1次正向循环后:
120 51  44  10  77  34  79  68  72  74  15  55  88
121 第1次反向循环后:
122 10  51  44  15  77  34  79  68  72  74  55  88
123 
124 第2次循环前:
125 10  51  44  15  77  34  79  68  72  74  55  88
126 第2次正向循环后:
127 10  44  15  51  34  77  68  72  74  55  79  88
128 第2次反向循环后:
129 10  15  44  34  51  55  77  68  72  74  79  88
130 
131 第3次循环前:
132 10  15  44  34  51  55  77  68  72  74  79  88
133 第3次正向循环后:
134 10  15  34  44  51  55  68  72  74  77  79  88
135 第3次反向循环后:
136 10  15  34  44  51  55  68  72  74  77  79  88
137 
138 第4次循环前:
139 10  15  34  44  51  55  68  72  74  77  79  88
140 第4次正向循环后:
141 10  15  34  44  51  55  68  72  74  77  79  88
142 
143 完成排序后:
144 10  15  34  44  51  55  68  72  74  77  79  88
145 请按任意键继续. . .
146 */

 双向冒泡排序的时间复杂度与单向相同。

(3)单向冒泡改进

按照双向冒泡排序交换标志的原则,将单向冒泡也加以实现。

改进实现,示例代码如下:

  1 #include <iostream>
  2 using namespace std;
  3  
  4 #define SWAP(x, y) { int t; t = x; x = y; y = t; }
  5 #define SIZE 5
  6  
  7 void InitArray(int br[])
  8 {
  9     for (int i = 0; i < SIZE; ++i)
 10     {
 11         br[i] = (rand() + 10) % 50;
 12     }
 13 }
 14  
 15 void PrintArr(int ar[])
 16 {
 17     for (int i = 0; i < SIZE; ++i)
 18     {
 19         cout << ar[i] << "   ";
 20     }
 21     cout << endl;
 22 }
 23 
 24  void test_bubble_sort(int ar[], int n)  
 25  {  
 26      if (NULL == ar || 0 == n)
 27      {
 28          return;
 29      }
 30 
 31      bool changeFlag = false;
 32      for (int i = 0; i < n; ++i)  
 33      {  
 34          cout << "i==" << i << " " << endl;
 35          changeFlag = false;
 36          for (int j = 0; j < n - i; ++j)  
 37          {
 38              cout << "  " << "j==" << j << " << ";
 39              if (ar[j] > ar[j + 1]) 
 40              {
 41                  SWAP(ar[j], ar[j + 1]);  
 42                  if (!changeFlag)
 43                      changeFlag = true;
 44              }
 45 
 46              PrintArr(ar);
 47          }
 48 
 49          if (!changeFlag)
 50              break;
 51       }  
 52  }
 53 
 54 void Test_Bubble_Sort(int ar[], int n) 
 55 {  
 56     if (NULL == ar || 0 == n)
 57     {
 58         return;
 59     }
 60 
 61     for (int i = 0; i < n; ++i)  
 62     {
 63         cout << "i==" << i << " " << endl;
 64         for (int j = 0; j < n - i; ++j)  
 65         {
 66             cout << "  " << "j==" << j << " << ";
 67             if (ar[j] > ar[j + 1]) 
 68             {
 69                 SWAP(ar[j], ar[j + 1]);
 70             }
 71             PrintArr(ar);
 72         }
 73     }  
 74 }
 75 
 76 void TestOrder(int ar1[], int ar2[])
 77 {
 78     cout << endl << "=====不加标志位测试=====" << endl;
 79     cout << endl << "排序前数据:" << endl;
 80     PrintArr(ar1);
 81     cout << endl << "测试排序过程数据:" << endl;
 82     Test_Bubble_Sort(ar1, SIZE - 1);
 83     cout << endl << "排序后数据:" << endl;
 84     PrintArr(ar1);
 85 
 86     int* ar = (ar2 != NULL) ? ar2 : ar1;
 87     cout << endl << "=====加标志位测试=====" << endl;
 88     cout << endl << "排序前数据:" << endl;
 89     PrintArr(ar);
 90     cout << endl << "测试排序过程数据:" << endl;
 91     test_bubble_sort(ar, SIZE - 1);
 92     cout << endl << "排序后数据:" << endl;
 93     PrintArr(ar);
 94 }
 95 
 96 void  main()
 97 {
 98     // 一般情况下
 99     cout << "++++++++++++++++++++++++++++" << endl;
100     cout << "++++++++++一般情况++++++++++" << endl;
101     int a[SIZE], b[SIZE];
102     InitArray(a);
103     InitArray(b);
104     TestOrder(a, b);
105 
106     // 特殊情况下1:数据默认有序
107     cout << endl << "++++++++++++++++++++++++++++" << endl;
108     cout << "++++++++++默认有序++++++++++" << endl;
109     int ar[SIZE] = {12, 23, 34, 45, 56};
110     TestOrder(ar, NULL);
111 
112     // 特殊情况下2:数据默认倒序
113     cout << endl << "++++++++++++++++++++++++++++" << endl;
114     cout << "++++++++++默认倒序++++++++++" << endl;
115     int br1[SIZE] = {90, 88, 76, 54, 32};
116     int br2[SIZE] = {90, 88, 76, 54, 32};
117     TestOrder(br1, br2);
118 
119     system("pause");
120 }
121 
122 // run out:
123 /*
124 ++++++++++++++++++++++++++++
125 ++++++++++一般情况++++++++++
126 
127 =====不加标志位测试=====
128 
129 排序前数据:
130 1   27   44   10   29
131 
132 测试排序过程数据:
133 i==0
134   j==0 << 1   27   44   10   29
135   j==1 << 1   27   44   10   29
136   j==2 << 1   27   10   44   29
137   j==3 << 1   27   10   29   44
138 i==1
139   j==0 << 1   27   10   29   44
140   j==1 << 1   10   27   29   44
141   j==2 << 1   10   27   29   44
142 i==2
143   j==0 << 1   10   27   29   44
144   j==1 << 1   10   27   29   44
145 i==3
146   j==0 << 1   10   27   29   44
147 
148 排序后数据:
149 1   10   27   29   44
150 
151 =====加标志位测试=====
152 
153 排序前数据:
154 34   38   18   22   24
155 
156 测试排序过程数据:
157 i==0
158   j==0 << 34   38   18   22   24
159   j==1 << 34   18   38   22   24
160   j==2 << 34   18   22   38   24
161   j==3 << 34   18   22   24   38
162 i==1
163   j==0 << 18   34   22   24   38
164   j==1 << 18   22   34   24   38
165   j==2 << 18   22   24   34   38
166 i==2
167   j==0 << 18   22   24   34   38
168   j==1 << 18   22   24   34   38
169 
170 排序后数据:
171 18   22   24   34   38
172 
173 ++++++++++++++++++++++++++++
174 ++++++++++默认有序++++++++++
175 
176 =====不加标志位测试=====
177 
178 排序前数据:
179 12   23   34   45   56
180 
181 测试排序过程数据:
182 i==0
183   j==0 << 12   23   34   45   56
184   j==1 << 12   23   34   45   56
185   j==2 << 12   23   34   45   56
186   j==3 << 12   23   34   45   56
187 i==1
188   j==0 << 12   23   34   45   56
189   j==1 << 12   23   34   45   56
190   j==2 << 12   23   34   45   56
191 i==2
192   j==0 << 12   23   34   45   56
193   j==1 << 12   23   34   45   56
194 i==3
195   j==0 << 12   23   34   45   56
196 
197 排序后数据:
198 12   23   34   45   56
199 
200 =====加标志位测试=====
201 
202 排序前数据:
203 12   23   34   45   56
204 
205 测试排序过程数据:
206 i==0
207   j==0 << 12   23   34   45   56
208   j==1 << 12   23   34   45   56
209   j==2 << 12   23   34   45   56
210   j==3 << 12   23   34   45   56
211 
212 排序后数据:
213 12   23   34   45   56
214 
215 ++++++++++++++++++++++++++++
216 ++++++++++默认倒序++++++++++
217 
218 =====不加标志位测试=====
219 
220 排序前数据:
221 90   88   76   54   32
222 
223 测试排序过程数据:
224 i==0
225   j==0 << 88   90   76   54   32
226   j==1 << 88   76   90   54   32
227   j==2 << 88   76   54   90   32
228   j==3 << 88   76   54   32   90
229 i==1
230   j==0 << 76   88   54   32   90
231   j==1 << 76   54   88   32   90
232   j==2 << 76   54   32   88   90
233 i==2
234   j==0 << 54   76   32   88   90
235   j==1 << 54   32   76   88   90
236 i==3
237   j==0 << 32   54   76   88   90
238 
239 排序后数据:
240 32   54   76   88   90
241 
242 =====加标志位测试=====
243 
244 排序前数据:
245 90   88   76   54   32
246 
247 测试排序过程数据:
248 i==0
249   j==0 << 88   90   76   54   32
250   j==1 << 88   76   90   54   32
251   j==2 << 88   76   54   90   32
252   j==3 << 88   76   54   32   90
253 i==1
254   j==0 << 76   88   54   32   90
255   j==1 << 76   54   88   32   90
256   j==2 << 76   54   32   88   90
257 i==2
258   j==0 << 54   76   32   88   90
259   j==1 << 54   32   76   88   90
260 i==3
261   j==0 << 32   54   76   88   90
262 
263 排序后数据:
264 32   54   76   88   90
265 请按任意键继续. . .
266 */

 事已至此。那么,至于为神马加标志位呢?请自行体会。

Good Good Study, Day Day Up.

顺序  选择  循环  坚持

 

作者:kaizen
声明:本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此声明,且在文章明显位置给出本文链接,否则保留追究法律责任的权利。
签名:顺序 选择 循环
原文地址:https://www.cnblogs.com/Braveliu/p/2848886.html