- 排序__比较排序
- 插入排序
直接插入排序
希尔排序
下面实现代码:
void InsertSort(int*a ,size_t n)
{
for (int i = 0; i< n - 1; ++i)
{
int end=i;
int temp = a[end+1]; //假装:temp就是下一个要插入的元素
while (end >= 0)
{
if (a[end] > temp)
{
a[end + 1] = a[end];
--end;
}
else
break;
}
a[end + 1] = temp; //最后把temp放到end+1的位置
}
}
void ShellSort(int*a ,size_t n)
{
int gap = n;
while (gap > 1)
{
gap = (gap/3) + 1;
for (size_t i = 0; i <(n - gap); ++i) //当第一个组完了时候所有组都完了,++i表示所有组是同时开始的
{
int end = i;
int temp = a[end + gap]; //下一个要预排序的元素
while (end >= 0)
{
if (a[end] > temp)
{
a[end + gap] = a[end];
end -=gap;
}
else
break;
}
a[end + gap] = temp;
}
}
}
- 选择排序
简单选择排序
堆排序
下面整个建堆的过程:
下面是实现代码
//选择排序
void SelectSort(int*a, size_t n)
{
int begin = 0;
int end = n - 1;
while (begin < end)
{
int maxIndex = end;
int minIndex = begin;
for (int i = begin; i <= end; ++i)
{
if (a[i]>a[maxIndex])
{
maxIndex = i;
}
if (a[i] < a[minIndex])
{
minIndex = i;
}
}
swap(a[begin],a[minIndex]);
if (maxIndex == begin)
maxIndex = minIndex;
swap(a[end],a[maxIndex]);
++begin;
--end;
}
}
//向下调整
void _AdjustDown(int* a,int root,size_t n)
{
int parent = root;
int child = parent * 2 + 1;
while (child < n) //这是一个完全二叉树,没有左孩子一定没有右孩子
{
if (child + 1<= n && a[child + 1]>a[child]) //当柚子树存在并且大于左子数时
++child;
if (a[parent] < a[child])
{
swap(a[parent], a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//堆排序
void HeapSort(int*a, size_t n)
{
//建大堆
for (int i = ((n - 2)/2); i >= 0; --i)
{
_AdjustDown(a,i,n);
}
//交换
int end = n-1;
while (end >0)
{
swap(a[0],a[end]);
_AdjustDown(a,0,end-1);
--end;
}
}
- 交换排序
快速排序:
下面是快排的递归和非递归:
//快排递归
void QuickSort(int* a, int left, int right)
{
if (left > right)
return;
//if (right - left < 5)
//{
// InsertSort(a,right-left+1);
//}
//这里进行单趟排序
//int div = partSort(a,left,right);
//int div = partSort1(a, left, right);
int div = partSort2(a, left, right);
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
//快排非递归
void QuickSortNoR(int* a, int left, int right)
{
stack<int> sta;
//这里存的是下标
sta.push(right);
sta.push(left);
while (!sta.empty())
{
int begin = sta.top();
sta.pop();
int end = sta.top();
sta.pop();
//这里进行单趟排序
//int div = partSort(a,begin,end);
//int div = partSort1(a, begin, end);
int div = partSort2(a, begin, end);
if (begin < div - 1)
{
sta.push(div-1);
sta.push(begin);
}
if (div + 1 < end)
{
sta.push(end);
sta.push(div+1);
}
}
}
左右指针法:
代码如下:
//左右指针法
int partSort(int*a, int begin, int end)
{
int mid = GetMidindex(a,begin,end);
swap(a[mid], a[end]);
int &key = a[end];
while (begin < end)
{
while (begin < end && a[begin] <= key)
++begin;
while (begin < end && a[end] >= key)
--end;
//这里begin找到了第一个大于key的值,end找到了小于key的值
if (begin < end)
swap(a[begin],a[end]);
}
//这里begin==end
swap(a[begin],key);
return begin;
}
挖坑法:
代码如下:
//挖坑法
int partSort1(int*a, int begin, int end)
{
int key = a[end]; //end是坑
while (begin < end)
{
while (begin < end && a[begin] <= key)
++begin;
//把begin这个位置的放到坑end中,然后坑变成了begin的位置
a[end] = a[begin];
while (begin < end && a[end] >= key)
--end;
//把end这个位置放到坑begin中,然后坑变成end
a[begin] = a[end];
}
//到了这里begin==end,所以坑就是这里
a[begin] = key;
return begin;
}
前后指针法:
代码如下:
//前后指针法
int partSort2(int*a, int begin, int end)
{
int cur = begin;
int prev =begin -1;
while (cur < end)
{
//这里cur是找比key也就是这里的a[end]小的,每次++prev和cur
if (a[cur] < a[end] && (++prev != cur))
swap(a[cur], a[prev]);
++cur;
}
//cur==end,交换prev+1和end(也就是我的key)
swap(a[end],a[++prev]);
return prev;
}
归并排序:
代码如下:
void _MergeSort(int*a, int left, int right, int*tmp)
{
if (left >= right)
return;
int mid = left + ((right - left) >> 1);
_MergeSort(a,left,mid,tmp);
_MergeSort(a, mid+1, right, tmp);
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int Index = left; //tmp的下标
//下面就是两段区间的合并a[left,mid],a[mid+1,right]
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
tmp[Index++] = a[begin1++];
else
tmp[Index++] = a[begin2++];
}
//有一个区间先结束了,就把另一个区间的剩下所有元素拷贝过去
while (begin1 <= end1)
tmp[Index++] = a[begin1++];
while (begin2 <= end2)
tmp[Index++] = a[begin2++];
//再把tmp里面的对应位置的元素拷贝回a[]的对应位置
//这里因为直到知道是int所以就用了memcpy,也可以用类型萃取,来区分深浅拷贝
memcpy(a+left,tmp+left,sizeof(int)*(right-left+1));
}
//归并排序
void MergeSort(int*a, size_t n)
{
int *tmp = new int[n];
_MergeSort(a ,0, n-1,tmp);
delete[] tmp;
}
// 非递归
void merge_sort(std::vector<int>& vec, int len) {
std::vector<int> tmp;
tmp.resize(vec.size());
for (int seg = 0; seg < len*2;) {
for (int i = 0; i < len; i += seg + seg+1+1) {
int index = i;
int leftStart = i;
int leftEnd = std::min(leftStart+seg,len-1);
int rightStart = std::min(leftEnd+1,len -1);
int rightEnd = std::min(rightStart+seg,len -1);
while(leftStart <= leftEnd && rightStart <= rightEnd){
if(vec[leftStart] < vec[rightStart]){
tmp[index++] = vec[leftStart++];
}else{
tmp[index++] = vec[rightStart++];
}
}
while(leftStart <= leftEnd){
tmp[index++] = vec[leftStart++];
}
while(rightStart <= rightEnd){
tmp[index++] = vec[rightStart++];
}
for(int j = i;j<=rightEnd;++j){
vec[j] = tmp[j];
}
}
if(seg == 0){
seg = 1;
}else {
seg = 2*seg+1;
}
}
}
- 排序__非比较排序
计数排序:
代码如下:
//计数排序
void Countsort(int* a,size_t n)
{
int max = a[0];
int min = a[0];
for (size_t i = 0; i < n; ++i)
{
if (a[i]>max)
max = a[i];
if (a[i] < min)
min = a[i];
}
int range = max - min + 1;
int* newbuf = new int[range];
memset(newbuf,0,range*sizeof(int));
for (size_t i = 0; i < n; ++i)
{
newbuf[a[i]-min]++;
}
int Index = 0;
for (size_t i = 0; i < range; ++i)
{
while (newbuf[i]--)
a[Index++] = i + min;
}
delete []newbuf;
}
基数排序:
实现顺序:
代码如下:
int Getdigits(int* a, size_t n)
{
int base = 10;
int digits = 1;
for (size_t i = 0; i < n; ++i)
{
while (a[i] >= base)
{
++digits;
base *= 10;
}
}
return digits;
}
//基数排序
void BaseSort(int* a, size_t n)
{
int* buckets = new int[n];
int digits = Getdigits(a,n);
int base = 1;
for (int i = 0; i < digits; ++i)
{
int Counts[10] = {0};
//counts记录第i位为num的个数
for (size_t i = 0; i < n; ++i)
{
int num = (a[i] / base) % 10;
Counts[num]++;
}
//求个位为i的在Startss的初始位置
int starts[10] = { 0 };
starts[0] = 0; //个位为0的起始位置肯定就从0开始
for (size_t i = 1; i < 10; ++i)
{
starts[i] = starts[i - 1] + Counts[i - 1]; //记录这位的在原数组中的起始位置,等于前一个数的起始位置+前一个的个数
}
//把数据从a[]放入到buckts[]里,在拷贝会a[]
for (size_t i = 0; i < n; ++i)
{
int num = (a[i] / base) % 10;
int& pos = starts[num];
buckets[pos] = a[i];
++pos;
}
base *= 10;
}
memcpy(a,buckets,sizeof(int)*n);
delete[] buckets;
}
下面我们对这些排序进行比较分析: