1.冒泡排序
整个排序过程为大的元素不断往后交换,每一轮排序排好一个元素。
class BubbleSort {
public:
int* bubbleSort(int* A, int n) {
int i=0;
while(i<n-1)
{
int j=0;
while(j<n-i-1)
{
if(A[j]>A[j+1])
{
int t=A[j];
A[j]=A[j+1];
A[j+1]=t;
}
++j;
}
++i;
}
return A;
}
};
以上代码的while也可以换成for或者混合使用,还可以做一些简单的改进,例如如果发现某一趟排序已经是有序的,则可以结束整个排序过程。
2.选择排序
每轮排序选出一个最小的放在前面正确的位置上。
class SelectionSort {
public:
int* selectionSort(int* A, int n) {
int i, j, min, tmp;
for (i = 0; i < n - 1; i++)
{
min = i;//假设要排的元素的位置就是当前位置
for (j = i + 1; j < n; j++)
if (A[j] < A[min])
min = j;
if (i != min) {
tmp = A[min];
A[min] = A[i];
A[i] = tmp;
}
}
return A;
}
};
3.插入排序
前面的元素都是有序的,以此把元素加入到前面有序的元素中。
class InsertionSort {
public:
int* insertionSort(int* A, int n) {
int i=0;
while (i<n)
{
int j=i;
while((j-1)>=0)
{
if(A[j]>A[j-1])
break;
else
{
int t=A[j-1];
A[j-1]=A[j];
A[j]=t;
}
--j;
}
++i;
}
return A;
}
};
4.归并排序
class MergeSort {
void mergesort2(int A[],int first,int mid,int last,int tmp[])
{
int i=first,j=mid+1,k=0;
while(i<=mid&&j<=last) tmp[k++]=A[i]<=A[j]?A[i++]:A[j++];
while (i<=mid) tmp[k++]=A[i++];
while (j<=last) tmp[k++]=A[j++];
for(i=0;i<k;++i) A[first+i]=tmp[i];
}
void mergesort1(int A[],int first,int last,int tmp[])
{
if(first<last)
{
int mid=(first+last)/2;
mergesort1(A,first,mid,tmp);//递归
mergesort1(A,mid+1,last,tmp);
mergesort2(A,first,mid,last,tmp);//合并
}
return;
}
public:
int* mergeSort(int* A, int n) {
int* tmp=new int[n];
if(tmp==NULL) return A;//内存不够用的情况
mergesort1(A,0,n-1,tmp);
delete []tmp;
return A;
}
};
排序示意图如下:
5.快速排序
每轮排序选择第一个元素为目标元素,比这个元素小的放在它左边,比它大的放在右边。
class QuickSort {
void quicksort(int A[],int left,int right)
{
int i,j,temp;
if(left>right)
return;
temp=A[left];
i=left;
j=right;
while(i!=j)
{
while(i<j&&A[j]>=temp)
--j;
while(i<j&&A[i]<=temp)
++i;
if(i<j)
swap(A[i],A[j]);
}
A[left]=A[i];
A[i]=temp;
quicksort(A,left,i-1);
quicksort(A,i+1,right);
}
public:
int* quickSort(int* A, int n) {
quicksort(A,0,n-1);
return A;
}
};
例如待排序元素为:
4 5 6 7 8 1 2 3
第一遍排序过程为:
4 5 6 7 8 1 2 3
4 3 6 7 8 1 2 5
4 3 2 7 8 1 6 5
4 3 2 1 8 7 6 5
1 3 2 4 8 7 6 5
6.堆排序
一.非递归方式
class HeapSort {
void buildheap(int A[],int size)
{
int i;
for(i=size/2-1;i>=0;i--)
{
adjustheap(A,i,size);
}
}
void adjustheap(int A[],int i,int size)
{
int j=i*2+1;//子节点
while(j<size)
{
if(j+1<size&&A[j]<A[j+1]) ++j;
if(A[i]>A[j]) break;
swap(A[i],A[j]);
i=j;
j=2*i+1;
}
}
public:
int* heapSort(int* A, int n) {
int i;
buildheap(A,n);
for(i=n-1;i>=0;i--)
{
swap(A[i],A[0]);
adjustheap(A,0,i);
}
return A;
}
};
二.递归方式
class HeapSort {
public:
void build_heap(int *tree, int n)
{
for (int i = (n - 1)/2; i >= 0; --i) {//从最后一个父节点开始由下往上建堆
heapify(tree, n, i);
}
}
void heapify(int* tree, int n, int i)
{
if (i >= n) return; //可以没这个
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
if (c1 < n && tree[c1] > tree[max]) { //一定要判断c1<n,防止越界
max = c1;
}
if (c2 < n && tree[c2] > tree[max]) { //一定要判断c2<n,防止越界
max = c2;
}
if (max != i) {
swap(tree[max], tree[i]);
heapify(tree, n, max);
}
}
int* heapSort(int* A, int n) {
build_heap(A, n);
for (int i = n - 1; i >= 0; --i) {
swap(A[0], A[i]);
//build_heap(A, i);
heapify(A, i, 0);//i值需要变化
}
return A;
}
};
已知堆上一个节点i,那么它的父节点为(i-1)/2,左孩子为2*i+1,右孩子为2*i+2
7.希尔排序
class ShellSort {
public:
int* shellSort(int* A, int n) {
int i,j,gap;
for(gap=n/2;gap>0;gap/=2)
for(i=gap;i<n;++i)
for(j=i-gap;j>=0&&A[j]>A[j+gap];j-=gap)
swap(A[j],A[j+gap]);
return A;
}
};
和冒泡排序比较像,相当于多趟步长不一样的冒泡排序。
8.桶排序
桶排序并不是一种排序算法,而是一种排序思想。包括计数排序,基数排序等。
一.计数排序
class CountingSort {
public:
int* countingSort(int* A, int n) {
int imax=A[0];
int imin=A[0];
for(int i=0;i<n;++i)
{
if(A[i]>imax) imax=A[i];
if(A[i]<imin) imin=A[i];
}
int range=imax-imin+1;
int *count=new int[range];
memset(count,0,sizeof(int)*range);
for(int i=0;i<n;++i)
{
count[A[i]-imin]++;
}
int index=0;
for(int i=0;i<range;++i)
{
while(count[i]--)
{
A[index++]=i+imin;//从桶里面倒出来
}
}
delete []count;
return A;
}
};
二.基数排序
class RadixSort {
int maxbit(int A[],int n)
{
int b=1;
int p=10;
for(int i=0;i<n;++i)
{
while(A[i]>=p)
{
p*=10;
++b;
}
}
return b;
}
public:
int* radixSort(int* A, int n) {
int b=maxbit(A,n);
int *tmp=new int[n];
int *count=new int[10];
int i,j,k;
int radix=1;
for(i=1;i<=b;++i)
{
memset(count,0,sizeof(int)*10);
for(j=0;j<n;j++)
{
k=(A[j]/radix)%10;
count[k]++;
}
for(j=1;j<10;++j)
count[j]+=count[j-1];//累加起来,数字越大,越靠后
for(j=n-1;j>=0;j--)
{
k=(A[j]/radix)%10;
tmp[count[k]-1]=A[j];
count[k]--;
}
for(j=0;j<n;j++)
A[j]=tmp[j];
radix*=10;
}
delete []tmp;
delete []count;
return A;
}
};
9.其他排序相关
一.小范围排序
class ScaleSort {
public:
void build_heap(int *tree, int k)
{
for (int i = (k - 1)/2; i >= 0; --i) {//从最后一个父节点开始由下往上建堆
heapify(tree, k, i);
}
}
void heapify(int* tree, int k, int i)
{
if (i >= k) return;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int min = i;
if (c1 < k && tree[c1] < tree[min]) {
min = c1;
}
if (c2 < k && tree[c2] < tree[min]) {
min = c2;
}
if (min != i) {
swap(tree[min], tree[i]);
heapify(tree, k, min);
}
}
vector<int> sortElement(vector<int> A, int n, int k) {
int tree[A.size()];
std::copy(A.begin(), A.end(), tree);
for (int i = 0; i <= n - k; ++i) {
build_heap(&tree[i], k);
}
for (int i = n-k+1; i < n; ++i) {
build_heap(&tree[i], --k);
}
A.clear();
for (int i = 0; i < n; ++i)
A.push_back(tree[i]);
return A;
}
};
二.重复值判断
要求空间复杂度为O(1)
static void adjustheap(vector<int>&A,int i,int size)
{
int j=i*2+1;//子节点
while(j<size)
{
if(j+1<size&&A[j]<A[j+1]) ++j;
if(A[i]>A[j]) break;
swap(A[i],A[j]);
i=j;
j=2*i+1;
}
}
void buildheap(vector<int>&A,int size)
{
int i;
for(i=size/2-1;i>=0;i--)
{
adjustheap(A,i,size);
}
}
void heapSort(vector<int>&A, int n) {
int i;
buildheap(A,n);
for(i=n-1;i>=0;i--)
{
swap(A[i],A[0]);
adjustheap(A,0,i);
}
}
class Checker {
public:
bool checkDuplicate(vector<int> a, int n) {
heapSort(a,n);
for(int i=1;i<n;++i)
{
if(a[i]-a[i-1]==0)
return true;
}
return false;
}
};
三.合并有序数组
class Merge {
public:
int* mergeAB(int* A, int* B, int n, int m) {
int i=n-1,j=m-1,k=n+m-1;
while(i>=0&&j>=0) A[k--]=A[i]>=B[j]?A[i--]:B[j--];
while(j>=0) A[k--]=B[j--];
return A;
}
};
四.三色排序
只有0,1,2三个值元素排序,要求时间复杂度为O(n)
class ThreeColor {
public:
vector<int> sortThreeColor(vector<int> A, int n) {
int left=-1;
int right=n;
int index=0;
while(index<right){
if(A[index]==0){
swap(A,++left,index++);
}else if(A[index]==2){
swap(A,index,--right);
}else{
index++;
}
}
return A;
}
void swap(vector<int> &A,int i,int j){
int temp=A[i];
A[i]=A[j];
A[j]=temp;
}
};
五.最短子数组
class Subsequence {
public:
int shortestSubsequence(vector<int> A, int n) {
int max=A[0],left=0;//从左向右正常顺序一直增大,碰见一个小的逆序,记录下来
int min=A[n-1],right=0;//从右向左正常顺序一直减小,碰见一个大的逆序,记录下来
int i=0,j=n-1;
while(i<n)
{
if(A[i]>=max)
max=A[i];
else
left=i;
++i;
}
while(j>=0)
{
if(min>=A[j])
min=A[j];
else
right=j;
--j;
}
return (left-right)>0?(left-right+1):0;
}
};
六.相邻两数最大差值
class Gap {
public:
int maxGap(vector<int> A, int n) {
if(n<=1)
return 0;
int _max=A[0],_min=A[0];
for(int i=1;i<n;++i)
{
if(A[i]>_max)
_max=A[i];
else if(A[i]<_min)
_min=A[i];
}
vector<int> ma(n+1,INT_MIN);
vector<int> mi(n+1,INT_MAX);
int L=_max-_min;
int cur;
for(int i=0;i<n;++i)
{
cur=(double)(A[i]-_min)/L*n;
ma[cur]=max(A[i],ma[cur]);//记录桶里面的最大值
mi[cur]=min(A[i],mi[cur]);//记录桶里面的最小值
}
int res=0;
int pre=ma[0];
for(int i=1;i<n+1;++i)
{
if(mi[i]!=INT_MAX)
{
res=max(res,mi[i]-pre);//记录当前桶的小值与上个桶最大值之间的差值的最大值
pre=ma[i];
}
}
return res;
}
};
七.大数据量排序问题
首先要分析待排序数据
(1)数据库
(2)分治法
(3)桶排序,包括位图排序,计数排序等
非稳定排序:快希选堆
参考资料:
用堆处理大数据量的topN问题和排序问题_top-n 堆排序-CSDN博客
https://www.cnblogs.com/Draymonder/p/10698967.html
https://www.cnblogs.com/kex1n/p/7246512.html?utm_source=itdadao&utm_medium=referral
数据量很大的排序问题 大量数据如何排序_大量数据排序-CSDN博客