排序分为冒泡排序,选择排序,插入排序,希尔排序,合并排序,快速排序,堆排序等
等,本篇文章我来详细解析冒泡排序,选择排序,直接插入排序。
我们学会一种排序算法,只要是学会这种算法的思想,而不是单纯的记忆代码~~
(一)冒泡排序:
算法思想:通过一趟冒泡排序,将最大的元素放在最后一个位置(假如从小到大排序),
或者将最小的元素放在最后一个位置(假如从大到小排序)。下边我用图来解释这个思想
下边我来给出冒泡排序的代码(从小到大排序):
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
void bottle_sort(int arr[], int len)
{
int i = 0;
int j = 0;
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
for (i = 0;i < len - 1;i++)
{
for (j = 0;j < len - i - 1;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[5] = {5,6,3,2,1};
int i = 0;
bottle_sort(arr,5);
for (i = 0;i < 5;i++)
{
printf("%d ",arr[i]);
}
system("pause");
return 0;
}
这段代码是非常正确的代码,可以得到正确的结果。可是如果给出这样一组数据:2,9,8,7,6(同样要求从大到小排序),你还要比较4趟吗??第1趟比较完后,2就排在
最后,这组数据就已经有序了,所以,后边的几趟排序就是浪费时间~~下边我来给出优
化代码:(下边的代码只给出实现部分,测试部分省略)
<pre name="code" class="cpp">void bottle_sort(int arr[], int len)
{
int i = 0;
int j = 0;
int flag = 0;
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
for (i = 0;i < len - 1;i++)
{
flag = 0;
for (j = 0;j < len - i - 1;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 1;
}
}
if (flag == 0)
{
break;
}
}
}
这段代码就比前边那段代码好一点,如果我们发现某一趟就没有进行交换,我们就认为
排序结束,退出。具体实现办法:进入外层循环时,我们给flag置一个数,比如置0,如
果进入if语句,就改变flag的值。出了内层循环,如果flag的值还是0,说明内存没有进行
交换,此时外层循环也结束。
怎么感觉冒泡排序写成这样就已经很不错了。。是吗??其实还有改进得到空间,如果
我们记住上一趟最后一次交换的位置,这一趟的交换只需要排序这个位置之前的元素。
下边给出代码:
void bottle_sort(int arr[], int len)
{
int i = 0;
int j = 0;
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
int k = len - 1;
int m = 0;
for (i = 0;i < len - 1;i++)
{
for (j = 0;j < k;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
m = j;
}//找到每一趟最后一次交换的位置
}
k = m;
}
}
要是把第2种和第3种方法结合起来,是不是更好呢~~~这里不给出代码了。
以上代码给出的是对整形数的排序,可是,如果要排序浮点数,排序结构体,是不是又
要再写一个函数~~c语言中的回调函数可以帮我们这么做~~(之前关于回调函数已经整
理过,这里再给出代码~~)
int compare(const void *elem1, const void *elem2)
{
return *(const int *)elem1 - *(const int *)elem2;
}
void sort(void *base, unsigned int num,
unsigned int byte, int(*cmp)(const void *elem1, const void *elem2))
{
char *pbase = (char *)base;
int flag = 0;
int i = 0;
int j = 0;
int k = 0;
const void *p1 = NULL;
const void *p2 = NULL;
for (i = 0;i < num - 1;i++)
{
flag = 0;
for (j = 0;j < num - 1 - i;j++)
{
p1 = (const void *)(pbase + j*byte);
p2 = (const void *)(pbase + (j + 1)*byte);
int ret = cmp(p1, p2);
if (ret > 0)
{
for (k = 0;k < byte;k++)
{//交换秘诀
pbase[j*byte + k] = pbase[j*byte + k] + pbase[(j + 1)*byte + k];
pbase[(j + 1)*byte + k] = pbase[j*byte + k] - pbase[(j + 1)*byte + k];
pbase[j*byte + k] = pbase[j*byte + k] - pbase[(j + 1)*byte + k];
}
flag = 1;
}
if (flag == 0)
break;
}
}
}
int main()
{
int(*cmp)(const void *elem1, const void *elem2) = compare;
int arr[4] = { 6,7,4,2 };
int i = 0;
sort(arr,4,4,cmp);
for (i = 0;i < 4;i++)
{
printf("%d ",arr[i]);
}
system("pause");
return 0;
}
(二)选择排序
算法思想:选择最大的元素或最小的元素放在它应该出现的位置。这句话你可能并不太
清楚,下边图解:
下边给出实现代码:
void select_sort(int arr[], int len)
{
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
int i = 0;
int j = 0;
int min = 0;//保存固定范围的最小值得下标
for (i = 0;i < len - 1;i++)
{
min = i;
for (j = i + 1;j < len;j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
if (i != min)//如果这个位置放的不是最小数,需要交换
{
int tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
}
边)。
(三)直接插入排序:
算法思想:将要处理的元素放在前边有序元素的合适的位置。图解:
下边给出实现代码:
void insert_sort(int arr[], int len)
{
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
int i = 0;
int j = 0;
int tmp = 0;
int k = 0;
for (i = 1;i < len;i++)
{
tmp = arr[i];
for (j = i - 1;j >= 0;j--)
{
if (arr[j] <= arr[i])
break;
}
for (k = i - 1;k > j;k--)
{
arr[k + 1] = arr[k];
}
arr[j+1] = tmp;
}
}
当前要处理的元素小的第一个位置。(假设从小到大排序)。内层第二个循环的作用是
移动,将内层循环1找到的位置的下一个位置到要处理元素的位置之间的数据统一后移
一个,然后将要处理的元素放在内层循环1找到的位置的下一个位置。我们仔细看一下
就会发现内层的循环之间好像有一定的联系,能不能把两个循环合成一个呢~~
void insert_sort(int arr[], int len)
{
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
int i = 0;
int j = 0;
int tmp = 0;
for (i = 1;i < len;i++)
{
tmp = arr[i];
for (j = i-1;(j >= 0) && (arr[j]>tmp);j--)//当要处理的元素比前边的元素小并且j还是大于等于0,
//就要发生移位
{
arr[j+1] = arr[j];
}//循环结束,j下标的元素是刚好小于要处理的元素(不满足arr[j]>tmp)或者是j=-1(不满足j>=0)
arr[j + 1] = tmp;//将要处理的元素放在上次j的下一个位置
}
}
前边,即就是2与4交换,2再与3交换。下边我来用代码实现以下:
void insert_sort(int arr[], int len)
{
if (len <= 0)
{
printf("数组长度不合理\n");
exit(EXIT_FAILURE);
}
int i = 0;
int j = 0;
int tmp = 0;
int m = 0;
for (i = 1;i < len;i++)
{
tmp = arr[i];
for (j = i - 1;(j >= 0) && (arr[j]>tmp);j--)
{
m = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = m;
}
}
}
关于排序先整理这么多,之后再整理出其他的排序方法。以上如有不合理的地方,希望
指出~~