/*
(一).快速排序
是对起泡排序的一种改进,通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键
字小,则可分别对这两部分继续进行排序,以达到整个序列有序.
交换顺序表L中子表L.r[low..high]的记录,使枢轴记录到位,并返回其所在位置,此时在它之前(后)的记录均不大(小)于它
时间复杂度为 n*logn,其平均性能最好,若初始记录序列按关键字有序或基本有序,快速排序将锐化为起泡排序
*/
int Partition(int SortData[], int low, int high)
{
int tmpData = SortData[low];//用于子表的第一个记录作枢轴记录
int temp=0;
while ( low<high )
{
//从表的两端交替的向中间扫描
while (low<high && SortData[high]>=tmpData)
{
high--;
}
//将比枢轴记录小的记录移到低端
SortData[low] =SortData[high];
while (low<high && SortData[low]<=tmpData)
{
low++;
}
//将比枢轴记录大的记录移到高端
SortData[high] =SortData[low];
}
//枢轴记录到位
SortData[low] =tmpData;
return low;//返回枢轴所在位置
}
void QuickSortData(int SortData[], int low, int high)
{
int offset;
if ( low<high )
{
offset = Partition(SortData, low, high);
QuickSortData(SortData, low, offset-1);//对前半个子表递归排序
QuickSortData(SortData, offset+1, high);//对后半个子表递归排序
}
}
/*
(二).直接插入排序
算法:经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,
使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。
首先比较L[i]和L[i-1],如果L[i-1]<=L[i],则L[1..i]已排好序,第i遍处理就结束了;
否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),
使得L[j] ≤L[j+1]时为止
优点:移动元素次数少,只需要一个辅助空间
时间复杂度n*n
当待排序记录的数量n很小时,这是一种很好的排序方法。但是n很大时,则不适合
*/
void InsertSortData(int SortData[], int Length)
{
int tmpData =0;
int i=0;
int j=0;
for(i=1; i<Length; i++)
{
if ( SortData[i] <SortData[i-1])
{
tmpData =SortData[i];
//数据往后移动
for (j=i-1; j>=0 && tmpData<SortData[j]; j--)
{
SortData[j+1] =SortData[j];
}
//将数据插入到j+1位置
SortData[j+1] =tmpData;
}
}
return;
}
/*
(三).归并排序
左边小左边,左边++;右边小取右边,右边++*/
template<typename T>
void merge(T array[], int low, int mid, int high)
{
int k;
T *temp = new T[high-low+1]; //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
int begin1 = low;
int end1 = mid;
int begin2 = mid + 1;
int end2 = high;
for (k = 0; begin1 <= end1 && begin2 <= end2; ++k) //比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
{
if(array[begin1]<=array[begin2])
temp[k] = array[begin1++];
else
temp[k] = array[begin2++];
}
if(begin1 <= end1) //若第一个序列有剩余,直接拷贝出来粘到合并序列尾
memcpy(temp+k, array+begin1, (end1-begin1+1)*sizeof(T));
if(begin2 <= end2) //若第二个序列有剩余,直接拷贝出来粘到合并序列尾
memcpy(temp+k, array+begin2, (end2-begin2+1)*sizeof(T));
memcpy(array+low, temp, (high-low+1)*sizeof(T));//将排序好的序列拷贝回数组中
delete temp;
}
template<typename T>
void merge_sort(T array[], unsigned int first, unsigned int last)
{
int mid = 0;
if(first<last)
{
mid = first/2 + last/2;
merge_sort(array, first, mid);
merge_sort(array, mid+1,last);
merge(array,first,mid,last);
}
}
/*
(四).堆排序
a[s]>=a[2*s] && a[s]>=a[2*s+1]*/
template<typename T>
void Max_heap(T a[],int S,int len)
{
int l = 2*S;
int r = 2*S+1;
int maxI = S;
T elem;
if (l < len && a[l] > a[maxI])
{
maxI = l;
}
if (r < len && a[r] > a[maxI])
{
maxI = r;
}
if (maxI != S)
{
elem = a[S];
a[S] = a[maxI];
a[maxI] = elem;
Max_heap(a,maxI,len);
}
}
template<typename T>
void HeapSort(T a[],int n)
{
int i;
T elem;
for (i = n/2;i>=0;i--)
{
Max_heap(a,i,n);
}
for (i= n-1;i>=1;i--)
{
elem = a[0];
a[0] = a[i];
a[i] = elem;
n = n-1;
Max_heap(a,0,n);
}
}
各种内排序方法的选择
1.从时间复杂度选择:
对元素个数较多的排序,可以选快速排序、堆排序、归并排序,元素个数较少时,可以选简单的排序方法。
2.从空间复杂度选择:
尽量选空间复杂度为O(1)的排序方法,其次选空间复杂度为O(log2n)的快速排序方法,
最后才选空间复杂度为O(n)二路归并排序的排序方法。
3.一般选择规则:
(1)当待排序元素的个数n较大,排序码分布是随机,而对稳定性不做要求时,则采用快速排序为宜。
(2)当待排序元素的个数n大,内存空间允许,且要求排序稳定时,则采用二路归并排序为宜。
(3)当待排序元素的个数n大,排序码分布可能会出现正序或逆序的情形,且对稳定性不做要求时,
则采用堆排序或二路归并排序为宜。
(4)当待排序元素的个数n小,元素基本有序或分布较随机,且要求稳定时,则采用直接插入排序为宜。
(5)当待排序元素的个数n小,对稳定性不做要求时,则采用直接选择排序为宜,若排序码不接近逆序,
也可以采用直接插入排序。冒泡排序一般很少采用。
各种排序方法的比较