排序——冒泡排序(三种方法)

冒泡排序的基本思想:

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

关于程序中4中冒泡排序写法的说明:

bubble_sort1:基本的冒泡排序的写法。

bubble_sort2:基本冒泡排序的不同写法,基本的冒泡排序是每次遍历,每次缩小范围1,这种办法是每次正向和反向遍历,每次缩小范围2,所以两者的比较次数也是一样的。

bubble_sort3:如果在某一趟的冒泡途中没有出现数据交换,那就只能是数据已经被排好序了,这样就可以提前得知数据排好序从而中断循环,消除掉不必要的比较。

bubble_sort4:如果在某一趟的冒泡途中最后的交换出现在pos的位置,那么表示pos位置以后都已经排好序,这样相比于基本冒泡每一次缩小遍历范围1而言有可能一次缩小的遍历范围>=1,所以这样也可以提高排序的效率。

程序代码如下:

#include <stdio.h>

int bubble_sort1(int num[], int n) /*最基本的冒泡排序法*/
{
	int i, j, tmp;
	int count = 0;

	for(i = 0; i < n-1; i++) /*冒泡一次放好一个数,冒泡n-1次就可以全部放置好*/
		for(j = 0; j < n-1-i; j++, count++) /*后面的i个数已经为有序序列*/
		{
			if(num[j] > num[j+1])
			{
				tmp = num[j];
				num[j] = num[j+1];
				num[j+1] = tmp;
			}
		}

	return count;
}

int bubble_sort2( int num[], int n) /*基本冒泡法的另一种写法*/
{
    int low = 0;
    int high= n -1; /*设置边界low和high*/
    int tmp, j, count = 0;
    while (low < high)
	{
        for(j=low; j < high; j++, count++) /*正向冒泡,找最大值*/
            if (num[j] > num[j+1])
			{
                tmp = num[j];
				num[j] = num[j+1];
				num[j+1] = tmp;
            }
        high --; /*更新冒泡区间*/
        for(j=high; j > low; j--, count++) /*反向冒泡,找最小值*/
            if (num[j] < num[j-1])
			{
                tmp = num[j];
				num[j] = num[j-1];
				num[j-1] = tmp;
            }
        low ++; /*更新冒泡区间*/
    }  

	return count;
}  

int bubble_sort3(int num[], int n) /*加入一标志性变量exchange,用于标志某一趟排序过程中是否有数据交换,
                                     如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,
									 则立即结束排序,避免不必要的比较过程。*/
{
	int i, j, tmp, exchange = 1, count =0;

	for(i = 0; i<n-1 && (exchange==1); i++) /*判断上一趟是否有数据交换,没有则表明排序已完成*/
		for(j = 0, exchange=0; j < n-1-i; j++, count++)
		{
			if(num[j] > num[j+1])
			{
				exchange = 1;
				tmp = num[j];
				num[j] = num[j+1];
				num[j+1] = tmp;
			}
		}

	return count;
}

int bubble_sort4(int num[], int n) /*加入一标志性变量pos,用于标志某一趟排序过程中最后交换数据的位置,
                                     那么在这个位置之后的数据都是已经排好序的,进而根据这个pos重新计算
									 还剩余的冒泡次数*/
{
	int i, j, tmp, pos, count =0;

	for(i=0; i < n-1; i=n-pos) /*n-pos表示已经排好序的个数,用来替代以前的i++方式计算已经排好序的个数*/
		for(j=0, pos=0; j < n-1-i; j++, count++) /*pos=0是必须的,不然没有交换的时候会出现死循环*/
		{
			if(num[j] > num[j+1])
			{
				tmp = num[j];
				num[j] = num[j+1];
				num[j+1] = tmp;
				pos = j+1; /*从j+1开始的往后的数据已经排好序*/
			}
		}

	return count;
}

void print_num(int num[], int n)
{
	int i;

	printf("[0-%d]: ", n-1);
	for(i=0; i < n; i++)
		printf("%d ", num[i]);
	printf("\n");
}

int main()
{
	int num1[] = {1, 9, 3, 5, 6, 2, 7, 10, 8, 4, 11, 15, 13, 12, 16, 14};
	int num2[] = {1, 9, 3, 5, 6, 2, 7, 10, 8, 4, 11, 15, 13, 12, 16, 14};
	int num3[] = {1, 9, 3, 5, 6, 2, 7, 10, 8, 4, 11, 15, 13, 12, 16, 14};
	int num4[] = {1, 9, 3, 5, 6, 2, 7, 10, 8, 4, 11, 15, 13, 12, 16, 14};
	int cmp_cnt;

	cmp_cnt = bubble_sort1(num1, sizeof(num1)/sizeof(int));
	print_num(num1, sizeof(num1)/sizeof(int));
	printf("Method1 compare count is: %d.\n\n", cmp_cnt);

	cmp_cnt = bubble_sort2(num2, sizeof(num2)/sizeof(int));
	print_num(num2, sizeof(num2)/sizeof(int));
	printf("Method2 compare count is: %d.\n\n", cmp_cnt);

	cmp_cnt = bubble_sort3(num3, sizeof(num3)/sizeof(int));
	print_num(num3, sizeof(num3)/sizeof(int));
	printf("Method3 compare count is: %d.\n\n", cmp_cnt);

	cmp_cnt = bubble_sort4(num4, sizeof(num4)/sizeof(int));
	print_num(num4, sizeof(num4)/sizeof(int));
	printf("Method4 compare count is: %d.\n\n", cmp_cnt);

	return 0;
}

程序运行结果截图:

排序——冒泡排序(三种方法)

时间: 2024-11-03 00:51:40

排序——冒泡排序(三种方法)的相关文章

[Excel VBA]自定义排序的三种方法

诸君好,前前期我们聊了VBA编程和数据的常规排序……VBA常用小代码105:Rang对象的排序操作……今天我们再聊下自定义排序……何谓自定义排序,就是按指定的顺序对数据源进行排序呗…… 今一共分享了三种方法.第1种方法是系统自带的OrderCustom,优点是代码简洁,缺点是自定义序列有字符长度限制(255个).第2种方法是字典+数组设置序列号,再使用了辅助列进行排序.优点是不会破坏单元格的形式和结构,比如单元格中存在的公式.背景等.第3种方法是只使用字典+数组,借助简单桶排序的技巧,直接对数据

JS数组去重的三种方法

<!DOCTYPE html> <html>     <head>         <meta charset="UTF-8">         <title>数组去重</title>     </head>     <body>         <script type="text/javascript">             //注意有一个元素是空的

利用Scala进行自定义排序的几种方法

# 第一种方法 package day05 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} object SortTest1 { def main(args: Array[String]): Unit = { val conf: SparkConf = new SparkConf().setAppName("SortTest1").setMaster("loca

分区自动挂载的三种方法

一.修改/etc/rc.local配置文件追加类似命令:mount /dev/sda1  /sda1 到配置文件最后一行 二,修改/etc/fstab配置文件追加类似命令:/dev/sda1   /sda1  ext4   defaults   0  0 到配置文件中 三,安装autofs服务yum install autofs 追加类似命令:sda1   -fstype=ext4  :/dev/sda1 到配置/etc/autofs.misc文件中重启服务: service autofs re

VMWARE虚拟机不能上网三种方法分析

bridged(桥接模式). NAT(网络地址转换模式) host-only(主机模式). 理论理解: 1.bridged(桥接模式) 在这处模式下,虚拟机等同于网络内的一台物理主机,可对手动设置IP,子网掩码,DNS,且IP地址要和主机的IP在同一网段内.这样,虚拟机就和主机如同连在一个HUB上的两台计算机,只要主机能上网,虚拟机也会在这种模式下上网. 2.host-only(主机模式) 在host-only模式中,所有的虚拟系统是可以相互通信的,但虚拟系统和真实的网络是被隔离开的. 提示:在

pdf文件怎么编辑 如何编辑pdf文件的三种方法

pdf文件越来越流行,工作中经常遇到需要修改pdf文件的情况.一般人的电脑上都为pdf文件安装了一个pdf阅读器,可它只能用来阅读查看pdf文件,并不能满足人们的编辑需求.那么pdf文件怎么编辑?下面小编给大家讲讲关于如何编辑pdf文件的三种方法.     方法一:直接编辑,一步到位     如果要对pdf文件进行编辑,我们则需要安装pdf编辑器.最新版的迅捷pdf编辑器可以编辑pdf文件中的任何内容,包括文字.图片.页眉页脚.添加注释等等.迅捷pdf编辑器如何编辑pdf文件?     首先需要

Android TextView里直接显示图片的三种方法

方法一:重写TextView的onDraw方法,也挺直观就是不太好控制显示完图片后再显示字体所占空间的位置关系.一般如果字体是在图片上重叠的推荐这样写.时间关系,这个不付源码了. 方法二:利用TextView支持部分Html的特性,直接用api赋图片.代码如下: //第一种方法在TextView中显示图片 String html = "<img src='" + R.drawable.circle + "'/>"; ImageGetter imgGett

Linux更新内核的三种方法

Centos内核升级的三种方法 在基于CentOS平台的工作过程中,难免有时需要升级或者降级内核以验证功能.调试性能或者更新整个系统.如果从头重新编译一个内核,由于现在内核特性越来越复杂,依赖的库或者工具也不少,加之重新编译耗时不菲,了解更新内核的多种方式就显得尤为必要.下面根据笔者最近的工作,总结了三种方法,供大家参考. 方法一 如果机器不能联网,可以下载现有内核包到本地机器,直接在本地更新 1.从http://ftp.scientificlinux.org/linux/scientific/

HashTable集合遍历的三种方法

hashtable集合遍历可以根据key,value以及key+value 示例代码: Hashtable table = new Hashtable(); Student stu = new Student(); stu.Name = "李四"; stu.Age = 18; Student stu1 = new Student(); stu1.Name = "张三"; stu1.Age = 18; Student stu2 = new Student(); stu