栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

改进冒泡排序(位运算、监察哨、定向冒泡排序)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

改进冒泡排序(位运算、监察哨、定向冒泡排序)

改进冒泡排序(循序渐进)

在文章中附上了所有代码,希望能对你有所帮助到你,喜欢的话就点个赞和关注吧,谢谢!

一下是基于普通冒泡排序的改进,编译的话是基于Linux系统的,如果是Windows等等的话可以直接复制代码用正常编译器编译运行就好啦,Linux编译命令行看不懂的话,可以进主页看看我后面发的gcc教程哦!

一:在原来的经典冒泡排序上如何改进使其减少占用的存储空间?

我发现这道题可以使用位运算,在思考过后发现用位运算确实可以减少一个中间变量的存储空间,改进代码如下:

#include 
void bubble_sort(int arr[], int len) {
    int i, j,ci_sum=0,tang_sum=0;
    for (i = 0; i < len - 1; i++){
        for (j = 0; j < len - 1 - i; j++){
            if (arr[j] > arr[j + 1]) {
                arr[j]=arr[j]^arr[j+1];
                arr[j+1]=arr[j+1]^arr[j];
                arr[j]=arr[j]^arr[j+1];
                ci_sum++;
            }}
            tang_sum++;
            }
            printf("次数:%dn,趟数:%dn",ci_sum,tang_sum);
}
int main() {
    int arr[]={22, 34, 3, 32, 82, 55, 4, 50, 37, 5, 64, 35, 9, 70,100};
    //int arr[]={3,4,5,9,22,32,34,35,37,50,55,64,70,82,100};
    int len = (int) sizeof(arr) / sizeof(*arr);
    bubble_sort(arr, len);//冒泡排序
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", arr[i]);
    printf("n排序结束,n");
    return 0;
}

 

运行正常:(位运算看不懂的朋友,我主页也有先关的教程哦)

而如果按照我一开始的想法用指针的话就会非常地麻烦,因为用指针,一旦被存储地址的变量的值发生改变,后面所有调用到这个指针的值也会随着改变,所以还是位运算简单!

二:判断是否中途排序已完成从而提前结束排序(同时减少排序次数)

了解过冒泡排序都知道,它是一趟又一趟地两两比较的,有一个问题就是如果我的数组在中途就已经排好了,或者我的数组根本就是已经排好的,那么再慢慢地排就会浪费非常多的资源,所以要改进一下,我尝试了往排序算法中引入一个“观察员”用来监视数据的交换情况,如果某一趟排序中,数据序列中的数据元素已经没有交换了,我们就可以认为排序已经完成,不需要再进行剩下的比较,结合一的位运算尝试编写代码如下:

#include 
void bubble_sort(int arr[], int len) {
    int i, j,ci_sum=0,tang_sum=0,flag=1;
    for (i = 0; i < len - 1&&flag==1; i++){
    	flag=0;
        for (j = 0; j < len - 1 - i; j++){
            if (arr[j] > arr[j + 1]) {
                arr[j]=arr[j]^arr[j+1];
                arr[j+1]=arr[j+1]^arr[j];
                arr[j]=arr[j]^arr[j+1];
                ci_sum++;
                flag=1;//有交换
            }}
            tang_sum++;
     }
     printf("次数:%dn,趟数:%dn",ci_sum,tang_sum);
}
int main() {
    int arr[]={22, 34, 3, 32, 82, 55, 4, 50, 37, 5, 64, 35, 9, 70,100};
    //int arr[]={3,4,5,9,22,32,34,35,37,50,55,64,70,82,100};
    int len = (int) sizeof(arr) / sizeof(*arr);
    bubble_sort(arr, len);//冒泡排序
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", arr[i]);
    printf("n排序结束,n");
    return 0;
}

其中flag就可以理解为我们的‘哨兵’(观察员)

运行效果:

 

可见使用同一个乱序的数组,该方法就已经可以节省了两次内部排序,和四趟循环,效果显著!

如果使用同一个已经有序的数组是什么效果?下面对比:

其实就是把我上面那个代码的乱序数组注释掉,把一个已经排好序的数组正常写入 

有哨兵运行效果:

一次都不用排,直接可以输出;

无哨兵:

 可见内部没有元素改动,但依然要循环14次

  • 双向冒泡排序(定向冒泡排序)

第一种写法:

升序:从低到高遍历把大值换后面去,即如果arr[num-i]>arr[num-i+1],那么就交换这两个的值,然后再从高到低遍历把小值换前面去,即如果arr[num-i+1]>arr[num-i],再交换这两个的值,不断循环上述过程即完成排序

类似于这样,然后再结合上面我们做的一、二,代码如下:

#include 
void bubble_sort(int arr[], int len)
{
 	int left = 0; // 初始化边界
 	int right = len - 1;
 	int cishu=0,tangshu=0;
 	while (left < right)
 	{
 	for (int i = left; i < right; i++)// 前半轮,就是将大元素放到后面,1----->num等
 		{
 		if (arr[i] > arr[i + 1])
 			{
 			arr[i]=arr[i]^arr[i+1];
                	arr[i+1]=arr[i+1]^arr[i];
                	arr[i]=arr[i]^arr[i+1];
                	cishu++;
 			}
 		}
 	right--;
 	for (int i = right; i > left; i--) // 后半轮,就是将小元素放到前面,num----->1等
 		{
 		if (arr[i - 1] > arr[i])
 			{
 			arr[i]=arr[i]^arr[i-1];
                	arr[i-1]=arr[i-1]^arr[i];
                	arr[i]=arr[i]^arr[i-1];
                	cishu++;
 			}
 		}
 	left++;
 	tangshu++;
 	}
 	printf("次数:%dn趟数:%dn",cishu,tangshu);
}

int main() {
    int arr[]={22, 34, 3, 32, 82, 55, 4, 50, 37, 5, 64, 35, 9, 70,100};
    //int arr[]={3,4,5,9,22,32,34,35,37,50,55,64,70,82,100};
    int len = (int) sizeof(arr) / sizeof(*arr);
    bubble_sort(arr, len);//冒泡排序
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", arr[i]);
    printf("n排序结束,n");
    return 0;
}

运行效果:

 相较于有哨兵的都减少了3趟,对于没有哨兵的减少了7趟,效果是真的显著!

第二种理解:

假设我们有num个元素,那么我们排序过程可以按下列过程理解:

1.遍历[num--------->1]位置.(我这里的num至1不是索引哈,只是数学上的位置,如果是索引应改为num-1--------->0)从底部(num位置)往上查找最小的值,并把最小值放到第1位置.

2.遍历[2--------->num]位置,从第2个位置往底部查找最大值,并把最大值放到第num位置.

3.遍历[num-1------>2]位置,从第num-1位置往上查找最小值,并把最小值放在第2位置.

4.遍历[3-------->num-1]位置,从第2个位置往底部查找最大值,并把最大值放到第num-1位置

我后面会再更一期这章噢,这部分代码会放在下一章,请前往我的主页查看噢,同时预计在下一章我还会改进上面代码比如加入“哨兵”等等,在下一章我也会补充一下c语言判断数组最大最小元素的方法,位运算等等,点个赞支持一下呗!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/882980.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号