虽然以前学习Java的时候对各种排序都进行学习和掌握,自己觉得也挺简单,每次用到的时候,都是去copy书上或者网上现成的,这两天在准备C语言考试的时候,才发现自己踏踏实实一行一行敲出来的代码运行不出正确结果来。当时就忍不了了。好多招聘面试都是开口就问数据结构的知识,而数据结构里面最简单的就是各种排序,这要不先搞定,就没法玩了。所以决定重新温习一遍。(这里全是以升序来讲解的,降序只需更改比较大小的那句代码就行)
但是在讲排序之前呢,不得不说说swap函数的写法,如果是值传递的话交换不会成功。如下:
void swap(int a, int b )
{
int temp=a;
a=b;
b=temp;
}
为什么呢,因为这里实参和形参拥有不同的内存空间,在执行的时候是把实参先复制到形参的内存空间中去,在swap里面只是对形参进行了交换,而我们真正想交换的实参数据却没有任何改变。
所以可以用传地址(即指针)的方式来进行交换,这样就都是对同一内存空间进行操作了。
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
1、选择排序
所谓选择,顾名思义就是以选择的方式,即每次通过比较选出一个最小的数的索引,然后把该索引处的数组元素放到适当位置。代码如下:
void select(int a[], int len)
{
int i, j, index;
for(i=0; i<len; i++)
{
index=i;
for(j=i+1; j<len; j++)
if(a[j]<a[index])
index=j;
swap(a+i, a+index);
}
}
2、插入排序
插入排序的思路是每次把一个数插入到已排好序的序列里面去,例如,一开始我们把数组的第一个元素看做已排好的序列(尽管只有一个元素),然后把数组的第二个元素通过比较插在该序列的适当位置,以此类推,当做第n次插入的时候,那么前n-1个数就已经是排好序的了。代码如下:
void insert(int a[], int len)
{
int i, j, temp;
for(i=1; i<len; i++)
{
if(a[i]<a[i-1])
{
temp=a[i];
j=i;
while(j>0 && a[j-1]>temp)
{
a[j]=a[j-1];
j--;
}
a[j]=temp;
}
}
}
3、冒泡排序
对于冒泡排序个人觉得是最好理解也是最好写的,四行代码就搞定了。不过还是说说这个过程吧,从开头依次进行两两比较,判断是否交换,所以一次冒泡的结果就是得到一个最大的放在末尾。代码如下:
void bubble(int a[], int len)
{
int i, j;
for(i=len-1; i>=0; i--)
for(j=0; j<i; j++)
if(a[j]>a[j+1])
swap(a+j, a+j+1);
}
4、快速排序
快速排序采用递归的思想,就是先取一个参考值,通过一趟排序将要排序的数据分割成独立的两部分,把比参考值小的放到其前面,比参考值大的放到其后面,然后再按此方法对这两部分数据分别进行快速排序。代码如下:
void quick(int a[], int len)
{
int i=0, j=len-1;
int val=a[0];
if(len>1)
{
while(i<j)
{
for(; j>i; j--)
if(a[j]<val)
{
a[i++]=a[j];
break;
}
for(; i<j; i++)
{
if(a[i]>val)
{
a[j--]=a[i];
break;
}
}
}
}
a[i]=val;
quick(a, i);
quick(a+i+1, len-i-1);
}
5、归并排序
归并排序的基本思路是,将数组分成 两组A,B,如果这两组组内的数据都是有序的,那么就可以很方便的将这两组数据进行排序。如何让这两组组内数据有序?可以将A,B组各自再分成两组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的两个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。代码如下:
/*复制数组,source:源数组,dest:目标数组,len:源数组长度,
first:目标数 组起始位置 */
void copy(int source[], int dest[],int len,int first)
{
int i;
int j=first;
for(i=0;i<len;i++)
{
dest[j] = source[i];
j++;
}
}
//归并过程
void merge(int a[],int left,int right)
{
int begin1 = left;
int mid = (left+right)/2 ;
int begin2 = mid+1;
int k=0;
int newArrayLen = right-left+1;
int *b = (int*)malloc(newArrayLen*sizeof(int));
while(begin1<=mid && begin2<=right)
{
if(a[begin1]<=a[begin2])
b[k++] = a[begin1++];
else
b[k++] = a[begin2++];
}
while(begin1<=mid)
b[k++] = a[begin1++];
while(begin2<=right)
b[k++] = a[begin2++];
copyArray(b,a,newArrayLen,left);
free(b);
}
//递归调用
void mergeSort(int a[],int left,int right)
{
int i;
if(left < right) // 保证至少有两个元素
{
i = (left+right)/2;
mergeSort(a,left,i);
mergeSort(a,i+1,right);
merge(a,left,right);
}
}