当前位置:   article > 正文

数据结构-经典排序算法:冒泡排序-白话文详解和c/c++代码实现_数据结构冒泡排序的算法实现

数据结构冒泡排序的算法实现

引言:

创造排序算法的先驱们真的是让人佩服,设计的太巧妙了。今天来讲一下冒泡排序,既是加深理解,也是一种分享。

思想:

冒泡排序是这样的,假如我当前有一个数组[x1,x2,x3,...,xn],这n个数是无序的,那么我要对该数组进行排序的话,假如要将该数组进行升序,我每一次都能从前往后(或从后往前)确定一个元素xi的具体位置,排在元素xi之前的元素都要比它小,它之后的元素都比它大,具体是先确定正数第一个位置还是倒数第一个位置,改变循环条件即可。这样讲可能有点抽象,那我们举个例子,逐步讲解冒泡排序的思想:

声明一个包含有8个元素的数组a[7],数组下标从0开始,所以这里为7时代表的第八个元素:

2

9

3

4

6

8

7

5

目标:

对该数组a[8]进行升序排序,即小的排在前面,大的排在后面。

解决思路:

先假设a[i]为我当前这一轮得出来的最小元素值的存储位置,a[j]和a[j-1]为当前两个元素作比较。

比如我当前开始遍历第一轮,确定一个最小值,并把它存在数组的第一个位置,i=0,即a[0]这个位置。

如何确定最小值?我从该数组的最后一个位置开始往前遍历作两两比较,遍历到当前存储最小值位置的下一个位置,第一轮比较具体到我的数组则是,a[7]与a[6]比较一次,a[6]与a[5]比较一次,a[5]与a[4]比较一次,...,a[1]与a[0]比较一次,在进行a[1]与a[0]比较的时候,如果a[1]小于a[0],则交换他们两个位置,否则不交换,此时a[0]存储的就是这一轮两两比较中的最小值;即我把j=7遍历到j=1;

因为a[0]已经存储了当前的最小值,所以下一轮的最小值应该存储在a[1]中,即i=1;下一轮开始:我依然从该数组的最后一个位置开始往前遍历作两两比较,只不过这一轮我只从后往前遍历到a[2],也就是a[7]与a[6]比较一次,a[6]与a[5]比较一次,a[5]与a[4]比较一次,...,a[2]与a[1]比较一次,不需要再进行a[1]与a[0]比较,因为a[0]已经存储了上一轮整个数组的最小值,现在的a[1]存储第二小值。

下一轮。。。,对于我声明的数组,循环遍历直到i=6即可,也是就数组长度减1的地方为最后一轮,因为当i=[6]的时候,我后面只剩一个元素i=7,这两个元素比较一次就可以确定这两个元素的最终位置了。

把思路演示出来看一下,记着目标是升序数组:

元素组a[7]:

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

6

8

7

5

(1)、当i=0,j=7时,a[7]=5,a[6]=7,a[7]<a[6],交换位置,a[6]=5,a[7]=7。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

6

8

5

7

(2)、当i=0,j=6时,a[6]=5,a[5]=8,a[6]<a[5],交换位置,a[6]=8,a[5]=5。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

6

5

8

7

(3)、当i=0,j=5时,a[5]=5,a[4]=6,a[5]<a[4],交换位置,a[5]=6,a[4]=5。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

5

6

8

7

(4)、当i=0,j=4时,a[4]=5,a[3]=4,a[4]>a[3],不交换位置。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

5

6

8

7

(5)、当i=0,j=3时,a[3]=4,a[2]=3,a[3]>a[2],不交换位置。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

9

3

4

5

6

8

7

(6)、当i=0,j=2时,a[2]=3,a[1]=9,a[2]<a[1],交换位置,a[2]=9,a[1]=3。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

3

9

4

5

6

8

7

(7)、当i=0,j=1时,a[1]=3,a[0]=2,a[2]>a[1],不交换位置。

a[0]

a[1]

a[2]

a[3]

a[4]

a[5]

a[6]

a[7]

2

3

9

4

5

6

8

7

以上就是一轮完整的遍历。接下来就是(i=1,j=7,6,5,4,3,2),(i=2,j=7,6,5,4,3),(i=3,j=7,6,5,4),(i=4,j=7,6,5),(i=5,j=7,6),(i=6,j=7),大家可以手推导加深理解。

第二部分:用数据结构来实现冒泡排序:

  1. 声明一个结构体,结构体中声明一个数组,再声明一个当前数数组长度,其中数组最大存储空间可以用关键字define来定义一个常量。

  1. #include <iostream>
  2. #define MaxSize 10
  3. using namespace std;
  4. typedef struct
  5. {
  6. int data[MaxSize];
  7. int length;
  8. }Sqlist;
  1. 由于在遍历数组的过程中需要进行两个数组的交换,所以可以定义一个函数,用于实现数组中的两个数的交换。

  1. void swap(Sqlist *L, int j)
  2. {
  3. int temp = L->data[j];
  4. L->data[j] = L->data[j-1];
  5. L->data[j-1] = temp;
  6. }
  1. 将排序过程单独定义成一个函数,这个函数是实现排序的核心。

  1. void maopao(Sqlist *L)
  2. {
  3. // i是从前往后遍历,遍历到倒数第二个位置
  4. for(int i=0;i<L->length-1;i++)
  5. {
  6. // flag用于标志,当前一轮如果没有进行位置交换,说明已经排好序,不需要继续遍历比较,结束函数
  7. bool flag = false;
  8. // j是从后往前遍历,从最后一个元素开始,比较j和j-1元素的大小,每一轮都遍历到i+1这个位置,因为i之前说的元素都已经有序
  9. for(int j=L->length-1;j>i;j--)
  10. {
  11. if(L->data[j] < L->data[j-1])
  12. {
  13. // 交换两个元素的位置,调用上面声明的swap函数
  14. swap(L, j);
  15. flag=true;
  16. }
  17. }
  18. if(flag==false)
  19. {
  20. return;
  21. }
  22. }
  23. return;
  24. }
  1. 主函数用于定义结构体数组中的元素以及长度,然后调用排序函数。

  1. int main()
  2. {
  3. Sqlist *L;
  4. L->length=8;
  5. L->data[0] = 2;
  6. L->data[1] = 9;
  7. L->data[2] = 3;
  8. L->data[3] = 4;
  9. L->data[4] = 6;
  10. L->data[5] = 8;
  11. L->data[6] = 7;
  12. L->data[7] = 5;
  13. maopao(L);
  14. for(int i = 0; i<L->length; i++)
  15. {
  16. cout<<"L->data["<<i<<"]="<<L->data[i]<<endl;
  17. }
  18. return 0;
  19. }
  1. 运行结果如图所示:

完整代码如下:

  1. #include <iostream>
  2. #define MaxSize 10
  3. using namespace std;
  4. typedef struct
  5. {
  6. int data[MaxSize];
  7. int length;
  8. }Sqlist;
  9. void swap(Sqlist *L, int j)
  10. {
  11. int temp = L->data[j];
  12. L->data[j] = L->data[j-1];
  13. L->data[j-1] = temp;
  14. }
  15. void swap1(Sqlist *L, int i, int j)
  16. {
  17. int temp;
  18. temp = L->data[i];
  19. L->data[i] = L->data[j];
  20. L->data[j] = temp;
  21. }
  22. // 冒泡排序
  23. void maopao(Sqlist *L)
  24. {
  25. for(int i=0;i<L->length-1;i++)
  26. {
  27. bool flag = false;
  28. for(int j=L->length-1;j>i;j--)
  29. {
  30. if(L->data[j] < L->data[j-1])
  31. {
  32. swap(L, j);
  33. flag=true;
  34. }
  35. }
  36. if(flag==false)
  37. {
  38. return;
  39. }
  40. }
  41. return;
  42. }
  43. int main()
  44. {
  45. Sqlist *L;
  46. L->length=8;
  47. L->data[0] = 2;
  48. L->data[1] = 9;
  49. L->data[2] = 3;
  50. L->data[3] = 4;
  51. L->data[4] = 6;
  52. L->data[5] = 8;
  53. L->data[6] = 7;
  54. L->data[7] = 5;
  55. maopao(L);
  56. for(int i = 0; i<L->length; i++)
  57. {
  58. cout<<"L->data["<<i<<"]="<<L->data[i]<<endl;
  59. }
  60. return 0;
  61. }

总结:冒泡排序是一个比较基础的排序,其运行时间复杂度最好为数组有序的情况,比较n-1次即可,最坏为数组反序的情况,比较n(n-1)/2,即时间复杂度为n的平方。

书写不易,谢谢点赞加收藏。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/556583
推荐阅读
相关标签
  

闽ICP备14008679号