上一篇学习了数据结构基本的查找算法,二分法和线性法,这篇文章谈一谈一些比较经典和常见的排序算法。
冒泡排序
冒泡排序即扫描数组,相邻元素两两比较,小数放左边,大数放右边,依次循环比较,每次都将一个最大值放在最后,即所谓的冒泡。即可完成排序。
下面是一个冒泡排序的接口:
void bubble_sort(int data[], size_t size)
{
int ordered = 1; //记录是否需要排序了
size_t j = 0;
size_t i = 0;
int swap = 0;
for(i; i < size - 1; ++i)
{
for(j = 0; j < size - 1; ++j)
{
if(data[j] > data[j + 1])
{
swap = data[j + 1];
data[j + 1] = data[j];
data[j] = swap;
ordered = 0;
}
}
if(ordered)
{
break; //ordered为0则要交换,为1则不需交换
}
}
}
冒泡排序的平均时间复杂度为O(N^2)
稳定排序(等值元素在排序前后的顺序保持不变)
对数据的有序性非常敏感
插入排序
所谓插入排序法,就是检查第i个数字,如果在它的左边的数字比它大,进行交换,这个动作一直继续下去,直到这个数字的左边数字比它还要小
下面是一个插入排序的接口:
void insert(int data[], int size)
{
int i;
int j;
for(i = 1; i < size; ++i)
{
for(j = i; j > 0 && data[i] < data[j-1]; --j)
{
data[j] = data[j - 1];
}
if(j != i)
{
data[j] = data[i];
}
}
}
插入排序的平均时间复杂度为O(N^2)
稳定排序
对数据有序性非常敏感,不做交换而是移动,优于冒泡排序
选择排序
在整个序列中寻找最小元素,与首元素交换,在剩余序列中寻找最小元素,与次元素交换,直到剩余序列中仅包含一个元素
下面是选择排序的接口:
void select(int data[], int size)
{
int i;
for(i = 0; i < size - 1; ++i)
{
int min = i;
int j;
for(j = i + 1; j < size; ++j)
{
if(data[j] < data[min])
{
min = j;
}
}
if(min != i)
{
int swap = data[i];
data[i] = data[min];
data[min] = swap;
}
}
}
平均时间复杂度O(N^2)
非稳定排序
对数据有序性不敏感,交换次数少,优于冒泡排序
这里介绍了三种基本排序方法,下篇文章单独介绍快速排序法。