1、插入排序
插入排序的工作原理是建立有序序列,对于未排序数据,在已排序的数据从后先前扫描,找到对应的位置后插入。
①从第一个元素开始,该元素被默认为有序序列。
②从下一个未排序数据开始,在已经排序的序列中从后往前扫描
③如果该元素小于已排序的元素,继续往前扫描
④重复③,直到找到该元素大于或等于已排序的元素的位置
⑤插入该元素
⑥重复②
代码:
void InsertSort(int *a,int size)
{
assert(a);
for (int i = 1; i < size; i++)
{
int index = i;
int end = index - 1; //已排序序列最后一个元素下标
int temp = a[index]; //保存未排序数据的值
while (end >= 0 && temp < a[end])
{
a[end + 1] = a[end]; //当为排序数据小于已排序序列数据时,把已排序数据向后移一位
end--; //继续往前扫描
}
a[end + 1] = temp; //找到未排序数据大于或等于已排序序列,或者整个已排序序列没有一个数小于未排序数据时
}
}插入排序对几乎已经排好序的数据进行操作时,效率很高。但插入排序一般来说是低效的,每次只能挪动数据一位。
2、希尔排序
希尔排序是更优化的插入排序。
其思想为:
把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。
void ShellSort(int *a, int size)
{
assert(a);
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = gap; i < size; i++)//比如当gap=4时,并不是让它分别进行4组插入排序,而是采用一种比较巧的方法,让i从gap开始每次加1,这样就能把4组插入排序,一次走完
{
int index = i;
int temp = a[index];
int end = index - gap;
while (end >= 0 && temp<a[end])
{
a[end + gap] = a[end];
end -= gap;
}
a[end + gap] = temp;
}
}
}3、堆排序
堆排序的思想就是如果是升序排序,则建最大堆,反之,则建最小堆。
建堆过程就是从最后一个非叶子节点直到跟节点向下对齐。假设我们现在要升序排序。即就是向下对齐时,把小的交换到父节点。
void AdjustDown(int *a,int size,int parent) //向下对齐
{
int child = parent * 2 + 1; //把左孩子的下标给child
while (child < size) //保证向下对齐直到child超出范围
{
if (child + 1 < size&&a[child + 1] > a[child]) //当右孩子>左孩子时,child变为右孩子下标
{
child++;
}
if (a[parent] < a[child])
{
swap(a[parent],a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int *a, int size)
{
assert(a);
for (int i = (size - 2) / 2; i >= 0; i--)
{
AdjustDown(a,size,i); //从图中下标为4的非叶子节点开始,进行向下对齐
}
for (int i = size - 1; i > 0; i--)
{
swap(a[0],a[i]); //把最大堆中的第一个元素和最后一个元素交换,此时最后一个元素最大
AdjustDown(a,i,0);//把剩余的元素建成最大堆
}
}原文:http://wanggaojun.blog.51cto.com/11409446/1761189