排序经常需要用到的函数:
void Swap(int data[], int i, int j){
int temp = data[i];
data[i] =data[j];
data[j] = temp;
}
一,冒泡排序。一种交换排序,两两比较相邻记录的关键字,如果反序则交换,直到没有反序为止。
//冒泡排序
void BubbleSort(int data[],int length){
for (int i = 0; i < length; ++i){
for (int j = i; j < length; ++j){
if (data[i]>data[j]){
Swap(data, i, j);
}
}
}
}
//冒泡排序优化
void BubbleSortPro(int data[], int length){
bool flag = true;
int len = length - 2;
for (int i = 0; i < length&&flag; ++i){
flag = false;
for (int j = len; j >= i; --j){
if (data[j]>data[j + 1]){
Swap(data, j, j + 1);
flag = true;
}
}
}
}//时间复杂度O(n^2)
二,选择排序。通过n-i次关键字间的比较,从n-i+1个记录中选择出关键字最小的记录,并和第i个记录交换。简单的说就是从数组的后面选出最小(或最大)的关键字交换到数组的前面。
//简单选择排序
void SelectSort(int data[], int length){
int min = 0;
for (int i = 0; i < length; ++i){
min = i;
for (int j = i + 1; j < length; ++j){
if (data[min]>data[j])
min = j;
}
if (i != min)
Swap(data, i, min);
}
}//O(n^2),但是性能上略优于冒泡
三,插入排序。将一个新纪录插入到已经排序好的有序表中,从而得到一个新的、记录数增加1的有序表。
//直接插入排序
void InsertSort(int data[], int length){
int tmp = 0,j,i;
for ( i = 1; i < length; ++i){
if (data[i] < data[i - 1]){
tmp = data[i];
for (j = i - 1; data[j] > tmp; --j)
data[j + 1] = data[j];
data[j + 1] = tmp;
}
}
}//O(n^2)
四,希尔排序(Shell Sort)。先解释什么是基本有序,所谓基本有序,就是小的关键字基本在前面,大的基本在后面,不大不小的基本在中间。希尔排序就是将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。
//希尔排序
void ShellSort(int data[], int length){
int i, j,tmp=0;
int increment = length;
do{
increment = (increment / 3)+1 ;
for (i = increment+1; i < length; ++i){
if (data[i]<data[i - increment])
{
tmp = data[i];
for (j = i - increment; j>=0&&tmp<data[j]; j-=increment){
data[j + increment] = data[j];
}
data[j + increment] = tmp;
}
}
} while (increment > 1);
}
五,堆排序。先解释什么是堆,所谓堆就是一棵具有每个结点的值都大于(或小于)或等于其左右孩子结点值的完全二叉树,当大于时是大顶堆,当小于时是小顶堆。将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。
void HeapAdjust(int data[], int start, int end){
int current = start;
int LC = 2 * current + 1;//左孩子位置
int tmp = data[current];
for (; LC <= end; current = LC, LC = 2 * LC + 1){
if (LC < end&&data[LC] < data[LC + 1])
++LC;
if (tmp > data[LC])
break;
else
{
data[current] = data[LC];
data[LC] = tmp;
}
}
}//时间复杂度O(nlogn)
void HeapSort(int data[], int length){
int i;
for (i = length / 2-1; i >0; --i){
HeapAdjust(data,i,length-1);
}
for (i = length-1; i >0; --i){
Swap(data, 0, i);
HeapAdjust(data, 0,i-1);
}
}
六,归并排序。归并排序是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列;再两两归并,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。
void Merge(int data[], int start, int mid, int end){
int *tmp = new int[end - start + 1];
int i = start;
int j = mid + 1;
int k = 0;
while (i <= mid&&j <= end){
if (data[i] <= data[j])
tmp[k++] = data[i++];
else
tmp[k++] = data[j++];
}
while (i <= mid)
tmp[k++] = data[i++];
while (j <= end)
tmp[k++] = data[j++];
//整合
for (i = 0; i < k; ++i){
data[start + i] = tmp[i];
}
delete[] tmp;
}
void MergeSort(int *data, int start, int end){
if (data==NULL||start >= end)
return;
int mid = (end + start) / 2;
MergeSort(data, start, mid);
MergeSort(data, mid + 1, end);
Merge(data, start, mid, end);
}//空间复杂度O(nlogn)
七,快速排序。快速排序是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
//快速排序
void QuickSort(int data[], int L,int R){
if (L < R){
int i, j, F;
i = L;
j = R;
F = data[i];
while (i < j){
while (i<j&&data[j]>F)
--j;
if (i < j)
data[i++] = data[j];
while (i < j&&data[i] < F)
++i;
if (i < j)
data[j--] = data[i];
}
data[i] = F;
QuickSort(data, L, i - 1);
QuickSort(data, i + 1, R);
}
}//时间复杂度O(nlogn)