一、选择排序
思想:
给合适的位置选择合适的数
#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,所以这种就是找到了;否则就是没找到。