深度剖析排序算法(一)——冒泡排序内涵及其改进方法。

本文详细介绍了冒泡排序算法的工作原理,包括如何使用物理现象进行排序,并通过两个嵌套循环实现升序或降序排列。文章进一步探讨了冒泡排序的改进方法,如使用标志位来优化算法效率,以及对算法进行动态终止的策略。

一:冒泡算法

冒泡算法的名字来历,来自于较轻的气泡会上升,较重的气泡会下降这么一个物理事实。

假设有一组数。排成列。存储在数组a[10]中。

我们可以利用这个物理现象来使其按照升序或者降序排列。

从头至尾部时,我们希望把最重的或最轻的放置头部。

这时我们知道,头部是最重的。这时,我们需要从第二个位置开始往尾部遍历。使剩下数目的最重的气泡放在第二个位置。

在选取哪个最重的气泡时,我们不得不从尾部向头部的方向进行遍历。

 

所以嵌套for循环需要写成如下形式:

for(i=0;i<n;i--)

   for(j=n-1;j>i;j++)

      {

 

      }

以上表述是将每趟比较的极值放置最前端。

每趟由后往前推

for(i=n-1;i>0;i--)

   for(j=0;j<i;j++)

      {

 

      }

以上表述是将每趟比较的极值放置最后端。

每趟由前往后推

 

 

这个时候我们需要考虑在排列求最大的过程。

每次排列。从尾部n-1开始,到i结束。

又必须一次只能比较交换相邻的两个。好像是滑动窗口一样。进来一个出去一个的样子。

所以。应该由第一个与第二比。从后向前时。是a[j]与a[j-1]。从前往后时应该是a[j]与      a[j+1]

所以补全上面如下

for(i=0;i<n;i++)

   for(j=n-1;j>i;j++)

      {

          if(a[j]>a[j-1])

              {

                   temp=a[j];

                   a[j]=a[j+1];

                   a[j+1]=temp

               }

 

      }

以上表述是将每趟比较的极值放置最前端。

每趟由后往前推

 

for(i=n-1;i>0;i--)

   for(j=0;j<i;j++)

      {

 

          if(a[j]>a[j+1])

              {

                   temp=a[j];

                   a[j]=a[j+1];

                   a[j+1]=temp

               }

      }

以上表述是将每趟比较的极值放置最后端。

每趟由前往后推。

我想我已经讲的非常清楚了。

这是一个嵌套for循环。

但是两个for循环之间是有一定的关联关系的。


下面给出他们的实际意义。

外层和内存的方向总是相反的。外层指针指的是无序队列结束的地方。也是有序队列逐渐增大的的尾部。内层就是利用窗口,将无序队列里的最值元素移动到有序队列的尾部。所以,内层的指针会从远向有序队列的尾部靠近。

外层for循环:需要遍历比较的队列。

但是我们知道当队列中只有一个数时,是不需要进行内存for循环的。所以,外层只需囊括遍历头n-1个即可。

内层for循环:对队列逐一进行遍历计较。

同样对于内层for循环。由于是两个两个的比较着前进。所以实质上只需比较队列长度leng-1次。所以。应注意两个for循环的写法。

记住以下要点即可。

1:两个for循环只涉及到三个数。0;n-1;i

2:先写=再写 <或者>。

 

3:如果内层循环递增,那么,与较大的比。

反之,如果内层递减。那么,与较小的比。

 

#include <stdio.h>
#include <stdlib.h>
#define m 20;
int bubbles(int a[],int n);
int bubbles2(int a[],int n);
void main()
{

	int i;
	int a[10];
	srand((unsigned int)time(0));
	for (i=0;i<10;i++)
	{
		a[i]=rand()%m;
	}
	for (i=0;i<10;i++)
	{
		printf("before sort:%d\n",a[i]);
	}


	bubbles2(a,10);
	for (i=0;i<10;i++)
	{
		printf("after sort:%d\n",a[i]);
	}



}
int bubbles(int a[],int n)
{
	int i,j,temp;
	for (i=0;i<n-1;i++)
	   for (j=n-1;j>i;j--)
	   {
		   if(a[j-1]>a[j])
		   {
			   temp=a[j-1];
			   a[j-1]=a[j];
			   a[j]=temp;

		   }
	   }
}

int bubbles2(int a[],int n)
{
	int i,j,temp;
	for (i=n-1;i>0;i--)
		for (j=0;j<i;j++)
		{
			if(a[j+1]>a[j])
			{
				temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;

			}
		}

}


 下面讨论一下对冒泡算法的改进方法:

(1):我们知道如果某趟比较遍历中,如果没有发生转换位置,那么可视为已经排序完毕。依据此条件进行改进。

设置标志位flag。若该趟有交换发生,则循序进行下一趟便利。否则停止。

程序如下:

int bubbles_inprove_flag2(int a[],int n)
{
	int i,j,temp;
	int flag;
	int num;
	num=0;
	flag=1;




	for (i=n-1;i>0;i--)

	if(flag>0)
	{
		flag=0;

		for (j=0;j<i;j++)
		{

			if(a[j+1]<a[j])
			{
				temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;
				flag=1;


			}
			num++;

		}
	

	}
	printf("num:%d\n",num);

}


 

 但是这并不能组织外层的遍历。只是进入内层循环时,使得由if的条件判断给阻挡住了。

再次改善后如下:

int bubbles_inprove_flag(int a[],int n)
{
	int i,j,temp;
	int flag;
	int num;
	num=0;
	flag=1;
	
		

	
	//for (i=n-1;i>0;)
i=n-1;
		while(flag>0)
		{
			flag=0;
			
		for (j=0;j<i;j++)
		{
			
			if(a[j+1]<a[j])
			{
				temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;
				flag=1;
				

			}
			num++;
			
		}
		i--;
		
	}
	printf("num:%d\n",num);

}


or(将flag信息融入外层判断中,即可及时阻止外层判断的继续进行)

   public static int bubble(int[] Array)
    {
        int Length = Array.Length;

        int flag = 1;
        for (var i = Length - 1; flag ==1 && i > 0; i--)
        {
            flag=0;//clear the flag
            for (var j = 0; j < i; j++)
            {
                if (Array[j] < Array[j + 1])
                {
                    var temp = Array[j];
                    Array[j] = Array[j + 1];
                    Array[j + 1] = temp;
                    flag = 1;// set the flag
                }
            }
            

        }
        return 1;
    }



结果如下:
 

 

 

 

 

#include <stdio.h>
#include <stdlib.h>

void main()
{
	int a[10]={5,8,4,3,9,6,1,2,7,0};

	int n;

	int i;
	int j;

	int temp;
	n=sizeof(a)/sizeof(int);
	for(i=0;i<n;i++)
	{
		printf("%d\n",a[i]);
	}

	for (i=1;i<n;i++)
	{
		for (j=0;j<n-i;j++)
		{
			if (a[j]<a[j+1])
			{
				temp=a[j];
				a[j]=a[j+1];
				a[j+1]=temp;
			}
		}
	}

	for(i=0;i<n;i++)
	{
		printf("%d\n",a[i]);
	}

}



 

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值