排序是一种非常常见,最基本的算法之一。常见的比较排序算法有以下四种:
1.插入排序
插入排序又分为直接插入排序和希尔排序。直接插入排序,指的是每次从序列中取出一个元素把它插入有序表中的合适的位置,使新的有序表仍然有序。具体方法是第一趟先比较前两个数,然后把第二个数插入到有序表中,第二趟把第三个数据插入有序表中,是有序表仍然有序。。。进行了(n-1)次插入,有序表完成排序。代码实现如下:
void Insertsort(int *a, size_t size)
{
assert(a);
for (int i = 1; i < size; ++i)
{
int index = i;
int tmp = a[index];
int end = index - 1;
while (end >= 0 && tmp < a[end])
{
a[end + 1] = a[end];
--end ;
a[end + 1] = tmp;
}
}
}
希尔排序实际上是一种分组插入的方法,是直接插入法的一种更高效的改进版本。其思想是:先取一个小于n的增量gap,把所有距离为gap的倍数的记录放在同一个组中,进行直接插入排序,然后再取第二个增量。其代码实现如下:
void shellsort(int *a,size_t size)
{
assert(a);
int gap = size;
while (gap > 1)
{
gap = gap / 3 + 1;
}
for (int i = gap; i < size; ++i)
{
int index = i;
int tmp = a[index];
int end = index - gap;
while (end >= 0 && tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
a[end + gap] = tmp;
}
}
}
2.选择排序
堆排序是一种特殊的选择排序,并且借助了堆特点。其代码实现如下:
void AdjustDown(int *a, size_t size, int root)
{
assert(a);
int child = root * 2 + 1;
while (child <size)
{
if (child + 1 < size&&a[child + 1] < a[child])
{
++child;
}
if (a[child] < a[root])
{
std::swap(a[child], a[root]);
root=child;
child=root*2+1;
}
else
{
break;
}
}
}
void Heapsort(int *a,size_t size)
{
assert(a);
for (int i = (size - 2) / 2; i >= 0; --i)
{
AdjustDown(a, size, i);
}
for (int i = 0; i < size ; ++i)
{
std::swap(a[0], a[size - 1 - i]);
AdjustDown(a,size-1-i,0);
}
}
注意,在这里AdjustDown是建大堆,排序的结果为降序,还有一种方法为建小堆AdjustDown,排序结果为升序,其代码实现如下:
void AdjustUp(int *a, size_t size, int child)
{
assert(a);
int root = (child - 1) / 2;
while (child >0)
{
if (a[child] > a[root])
{
std::swap(a[child], a[root]);
child=root;
root=(child-1)/2;
}
else
{
break;
}
}
}
3.交换排序
交换排序中冒泡排序,快速排序是应用最多的。冒泡排序的思想是:从第一对数据开始直到最后一对数据,比较他们的大小,如果第一个比第二个大就交换他们。。这样排下来,最后一个数就是最大的。剩下的所有元素也按这样排, 直到没有数据可以排时,排序完成。其代码实现如下:
void Bubblesort(int *a, int n)
{
assert(a);
for (int j = 0; j < 9; ++j)
{
for (int i = 0; i < 9 - j; ++i)
{
if (a[i]>a[i + 1])
{
int t = a[i];
a[i] = a[i + 1];
a[i + 1] = t;
}
}
}
}
快速排序是实际应用中最常见的一种算法,速度快效率高。快速排序是最优秀的排序算法。一般的实现方法如下:
void quicksort(int *a,int left,int right)
{
assert(a);
int tmp = a[left];
int i = left;
int j = right;
if (left > right)
{
return;
}
while (i != j)
{
while (a[j] >= tmp&&i < j)
{
j--;
}
while (a[i] <= tmp&&i < j)
{
i++;
}
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[left] = a[i];
a[i] = tmp;
quicksort(a,left, i - 1);
quicksort(a,i + 1, right);
}
这样的快速排序运行起来结果正确,但是还是不严谨,比如当给定数组的最后一个数就是整个数组中最大数时,程序运行的结果就出现错误。下次单独介绍。
4.归并排序
归并排序是采用分治法的一个典型的例子,即把待排序的序列分为若干个有序的子序列,再把子序列合并成一个整体有序的序列。其代码实现如下:
void mergeSection(int *a, int *temp, int begin1, int end1, int begin2, int end2)
{
int index = begin1;
while (begin1 <= end1&&begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[index++] = a[begin1++];
}
else
{
temp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
temp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
temp[index++] = a[begin2++];
}
}
void _mergesort(int *a, int *temp, int left, int right)
{
assert(a);
if (left < right)
{
int mid = left + (right - left) / 2;
_mergesort(a, temp, left, mid);
_mergesort(a, temp, mid + 1, right);
mergeSection(a, temp, left, mid, mid + 1, right);
memcpy(a + left, temp + left, sizeof(int)*(right - left + 1));
}
}
void mergesort(int *a, size_t size)
{
int *temp = new int[size];
_mergesort(a, temp, 0, size - 1);
delete[] temp;
}