学习C语言 7.30 排序

一、选择排序

思想:
         给合适的位置选择合适的数

#include <stdio.h>

int main(void)
{
	int a[]={3,21,12,4,2,6,7};
	int len=sizeof(a)/sizeof(a[0]);

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

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

	return 0;
}

外层循环是确定位置的,假设数组长度为6(len),那么最后是a[4]与a[5]进行比较,也就是意味着i只要取到4,4也就是len-2,所以for循环中,i<len-1;

里层循环是用来进行比较的,每次比较都会找出最小值,也就是说第一次会找出最小值,放在a[0],a[0]的值也就确定了,第二次会比较a[0]外的最小值,放在a[1],于是a[1]的值也确定了。由于j每次都要比到最后,所以j<len,因为是从后面的一个元素与前一个元素进行比较,所以j从i后一个元素开始,j=i+1。

二、冒泡排序

思想:
       一次冒出一个数 
       相邻两个元素,两两比较,小的放前,大的放后

#include <stdio.h>

int main(void)
{
	int a[]={23,45,32,56,7,8,9,2};
	int len=sizeof(a)/sizeof(a[0]);

	int i=0;
	int j=0;

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

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

	return 0;
}

外层循环是控制趟数的,躺数为len-1。假设数组长度为5;第一趟时,需要比较4次,第二趟比较3次,第三趟比较2次,第四趟比较1次,完成排序,从上面的变化可以看出比较次数受第几趟的影响而变化。设i表示第几趟,j表示比较次数,也就是说i=1,j=4;i=2,j=3;i=3,j=2;i=4,j=1。可以看出j=len-i。i总共有四趟,所以i会循环len-1,所以当i从1开始时,i<len;同理也可以让i从0开始,只需要让趟数为len-1即可。

里层循环是一趟的比较过程,改变i值的同时,也要修改j。冒泡比较是相邻的元素进行比较,每次会将最大值排到最后,也就是说第一趟将最大值排到最后,那么a[4]的值就确定了,第二趟会将a[4]排外,找出最大值放在a[3],于是a[3]的值也确定了。j会比较len-i次,所以当j从0开始,j<len-i(在i从1开始,i<len的前提)。如果i=0;i<len-1时,j=0;j<len-i-1(相当于i从1变成0,也就是-1,所有len-i也要-1)。如果i=len-1;i>0;--i时,j=0;j<i;++j(因为i只是控制总共len-1次趟数的,当i=4时,实际上还是第一趟,也就说j要比较4次,从0到i也就是4次,所以j<i)。

三、插入排序

思想:
        在有序序列中,找到合适的位置插入

#include <stdio.h>

int main(void)
{
	int a[]={13,7,2,5,3,43,35};
	int len=sizeof(a)/sizeof(a[0]);

#if 0
	int b[len];

	int i=0;
	for (i=0;i<len;++i)
	{
		int temp=a[i];  //拿数
		int j=i;  //准备要放的位置
		while(j>0&&b[j-1]>temp)
		{
			b[j]=b[j-1];  //往后挪一位
			--j;
		}
		b[j]=temp;  //插入数据
	}
#endif

    //原地插入
	int i=0;
	for (i=0;i<len;++i)
	{
		int temp=a[i];
		int j=i;
		while(j>0&&a[j-1]>temp)
		{
			a[j]=a[j-1];
			--j;
		}
		a[j]=temp;
	}

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

	return 0;
}

条件编译里的是通过另一个与a数组一样长的b数组,让b[0]=a[0],每次将a数组中的元素拿出,与前一个元素进行比较,如果前一个比拿来的元素大,就让前一个元素的值挪到后一位。当i=0时,不满足while的条件,所以b[0]=a[0],于是这种特殊情况也满足,不用单独写。

原地插入相比于通过使用数组b相差不大,将while中的b改为a即可。由于现在a[0]已经存在,不要拿a[0]这个数据了,所以i从1开始。

四、查找算法

二分查找(折半查找) 
     大前提:
        数据得是有序的
        
    思想:
        1. 找到中间位置的数, //下标 
        2. 拿这个数 和 要找的数比较 
        
        mid //下标  
        a[mid] > m 
        a[mid] < m
        
        3. 每次折一半,直到找到对应数组,或者 结束 

#include <stdio.h>

int main(void)
{
	int a[]={1,2,3,4,5,6};
	int len=sizeof(a)/sizeof(a[0]);
	int m;
	scanf("%d",&m);

	int begin=0;
	int end=len-1;
	while(end>=begin)
	{
		int mid=(begin+end)/2;

		if(m<a[mid])
		{
			end=mid-1;
		}
		else if(m>a[mid])
		{
			begin=mid+1;
		}
		else
		{
			break;
		}
	}

	if(end>=begin)
	{
		printf("yes!\n");
	}
	else
	{
		printf("no!\n");
	}
	return 0;
}

定义下标begin、end、mid(中间值),begin也就是开始,为0;end结束也就是len-1;中间值下标mid为首尾相加除以2。如果发现要找的数m比mid小,就将end挪到mid-1,如果挪到最后都没找到m,end就会挪到比begin小的位置,所以循环的条件是end>=begin。如果m比mid大,就将begin挪到mid+1的位置,同理如果没找到,begin会挪到比end大的位置,此时循环条件也不成立。如果相等,就证明找到了,直接break跳出循环。

循环结束有两种情况,一种就是break出来,一种是循环完出来,此时满足end>=begin,所以这种就是找到了;否则就是没找到。

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值