#include <iostream>
#include <stack>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cassert>
void PrintArr(int arr[], int n)
{
for(int i = 0; i < n; ++i)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
//冒泡排序
//n 为排序元素的个数
void BoubbleSort(int arr[], const int n)
{
//冒泡的总的趟数是n-1次
for(int i = 0; i < n -1; ++i)
{
//每趟冒泡前将flag置为0
int flag = 0;
//每一趟则冒泡的次数是n-i-1次,后面已经排好序的元素不需要冒泡了.
for(int j = 0; j < n - i - 1; ++j)
{
if(arr[j] > arr[j+1])
{
std::swap(arr[j], arr[j+1]);
flag = 1;
}
}
//如果某一趟冒泡中未发生交换,则说明元素都已经有序,直接退出.
if(flag == 0)
return;
}
}
//选择排序
void SelectSort(int arr[], const int n)
{
//本应该有几个书就扫描几次,但是实际上有n个数,扫描n-1次就可以了.
for(int i = 0; i < n -1; ++i)
{
//标记最小元素的下标,最开始假设第一个数就是最小的.
int min = i;
//每次都是在未排序的元素中找一个最小的.
//[0,i]是已经排序的,
//[i,n)都是未排序的
//每次找最小的数的时候要遍历到最后
for(int j = i + 1; j < n; ++j)
{
//如果j下标的元素小于最小的,则更新最小数的下标.
if(arr[j] < arr[min])
min = j;
}
//每次扫描结束,把真正最小的数放到已经有序的序列后
std::swap(arr[i], arr[min]);
}
}
//插入排序
void InsertSort(int arr[], const int n)
{
//在无序的元素中取一个插入到有序的序列中
//开始取第一个元素作为有序序列
int j = 0;
for(int i = 1; i < n; ++i)
{
//有序序列[0, i-1], 无序序列[i, n)
//取出无序序列中的第一个元素
int tmp = arr[i];
//升序
//将取出的无序元素依次和有序序列中的元素比较
j = i;
//while(j > 0 && tmp <= arr[j-1]) //循环1
//for(j = i; j > 0 && tmp <= arr[j-1]; --j) //循环2
for(j = i - 1; j >= 0 && tmp <= arr[j]; --j) //循环3
{
//如果该元素一直小于有序列表中的元素,则将有序列表中的元素依次往后移动,
//直到找到合适该元素的位置
//arr[j] = arr[j-1]; //循环1\循环2
arr[j+1] = arr[j]; //循环3
//--j; //循环1
}
//找到合适该元素的位置了,则将它放入到该位置
//arr[j] = tmp; //循环1\循环2
arr[j+1] = tmp; //循环3
}
}
//希尔排序
void ShellSort(int arr[], const int n)
{
//计算分组的增量,当增量为1,则正好是对所有元素进行排序,并结束.
for(int group = n / 2; group > 0; group /= 2)
{
//根据增量,对元素进行分组
for(int i = 0; i < group; ++i)
//对每组进行插入排序
//每组的第一个元素是有序序列
for(int j = i + group; j < n; j += group)
{
//取无序序列中的第一个元素和有序序列中的元素依次比较
if(arr[j] < arr[j-group])
{
int tmp = arr[j];
int k;
//进行比较的时候,k是要大于该组的起始位置i.
//这里很容易出差,网上好多都是在这里写错了.
//如果k>0的话,就会存在越界,产生段错误.
for(k = j; k > i && tmp <= arr[k-group]; k-= group)
{
arr[k] = arr[k-group];
}
arr[k] = tmp;
#if 0
k = j;
while(k > i && tmp <= arr[k-group])
{
arr[k] = arr[k-group];
k -= group;
}
arr[k] = tmp;
#endif
}
}
}
}
//快速排序
//优化:
//1.key三数取中法
//取最后一个,第一个,中间的一个,这三个数作比较,取出中间的值作为key
//为了防止代码改动,可以将取出的key先交换放到right-1的位置.
//2.可以优化递归的次数,当每个分组中的元素少于16个时,则使用插入排序.
//左右指针交换法
int Partion1(int arr[], int left, int right)
{
int key = arr[right-1]; //取最后一个数为基准数
int begin = left;
int end = right - 1;
while(begin < end)
{
//从左边找大于key的值,找的时候始终要保证begin < end.
//不然会越界(基准值是最大的,且刚好是最后一个元素)
while(begin < end && arr[begin] <= key) //找大的所以要小于等于
++begin;
//从右边找小于key的值,找的时候始终要保证begin < end.
//不然会越界(基准值是最大的,且刚好是最后一个元素)
while(begin < end && arr[end] >= key)//找小的所以要大于等于
--end;
//如果2个数找到了,则交换2个数的位置
if(begin < end) //排除循环越界退出的情况
{
std::swap(arr[end], arr[begin]);
//int tmp = arr[end];
//arr[end] = arr[begin];
//arr[begin] = tmp;
}
}
//left == begin
//比key大的都在右边,小的都在左边
//key为基准的这个数放到他自己的位置
if(end != right-1) //防止自己和自己交换,
//不然会进入死循环(如果找的key刚好是最大的)
std::swap(arr[end], arr[right-1]);
return end;
}
//左右指针挖坑法(和交换法很像)
int Partion2(int arr[], int left, int right)
{
int key = arr[right-1];
int begin = left;
int end = right - 1;
while(begin < end)
{
//从左找大于key的值
while(begin < end && arr[begin] <= key)
++begin;
//找到之后,用它将前面的坑填上
if(begin < end) //确保是找到了
{
arr[end] = arr[begin];
--end;
}
//找小于的
while(begin < end && arr[end] >= key)
--end;
if(begin < end)
{
arr[begin] = arr[end];
++begin;
}
}
//begin == end
if(end != right - 1)
arr[end] = key;
return end;
}
//前后指针法
int Partion3(int arr[], int left, int right)
{
int key = arr[right-1];
int cur = left;
//开始时pre在cur 的后面一个位置
//[注意]不能直接让pre = -1,因为cur的起始位置不一定在0处
int pre = cur - 1;
//prev 在cur 的后面,
//让cur 一直往后走:
// 如果cur 位置的数比key小,则让prev走一步.
// 再比较prev和cur 是不是在同一位置,如果不在同一位置,
// 则交换prev 和cur 处的元素.
// 在同一位置就cur 往后走一步.
// 如果cur位置的数比key 大,cur往后走一步.
#if 0
while(cur < right)
{
if(arr[cur] < key)
{
++pre;
if(pre != cur)
{
std::swap(arr[pre], arr[cur]);
}
}
++cur;
}
#endif
while(cur < right)
{
if(arr[cur] < key && ++pre != cur)
std::swap(arr[pre], arr[cur]);
++cur;
}
//防止取的key刚好为最大值,刚好在最后一个位置,自己和自己交换
if(++pre != right - 1)
std::swap(arr[pre], arr[right-1]);
return pre;
}
void QuickSortNotR(int arr[], int left, int right)
{
std::stack<int> s;
//先进后出
//右侧先入栈
s.push(right);
//左侧入栈
s.push(left);
while(!s.empty())
{
left = s.top(); //取栈顶元素
s.pop();//出栈
right = s.top();
s.pop();
//只要有1个以上元素就继续
if(left < right)
{
int div = Partion1(arr, left, right);
//先将右区间入栈
s.push(right);
s.push(div + 1);
//左区间入栈
s.push(div);
s.push(left);
}//endif
}//endwhile
}
void QuickSort(int arr[], int left, int right)
{
//有2个或2个以上的元素时才进行排序
if(right - left > 1)
{
//int div = Partion1(arr, left, right);
//int div = Partion2(arr, left, right);
int div = Partion3(arr, left, right);
//排序左边
QuickSort(arr, left, div);
//排序右边
QuickSort(arr, div+1, right);
}
}
//归并排序
void MergData(int arr[], int left, int mid, int right, int* tmp)
{
int beg1 = left, end1 = mid;
int beg2 = mid, end2 = right;
int index = left;
while(beg1 < end1 && beg2 < end2)
{
if(arr[beg1] < arr[beg2])
tmp[index++] = arr[beg1++];
else
tmp[index++] = arr[beg2++];
}
while(beg1 < end1)
tmp[index++] = arr[beg1++];
while(beg2 < end2)
tmp[index++] = arr[beg2++];
}
void _MergSort(int arr[], int left, int right, int* tmp)
{
if(right - left > 1)
{
//int mid = left + ((right - left) >> 1);
int mid = (left + right) / 2;
//排左半部分
_MergSort(arr, left, mid, tmp);
//排右半部分
_MergSort(arr, mid, right, tmp);
//将2个部分合并到辅助空间tmp中
MergData(arr, left, mid, right, tmp);
//将排好序的元素从辅助空间拷贝到原空间arr中
memcpy(arr + left, tmp + left, sizeof(arr[0]) * (right - left));
//下面这个是错误的, 每次拷贝的时候不都是从0开始的
//memcpy(arr, tmp, sizeof(arr[0]) * (right - left));
}
}
void MergSort(int arr[], int left, int right)
{
int *tmp = (int*)malloc(sizeof(arr[0]) * right);
if(tmp == NULL)
{
perror("malloc");
return;
}
_MergSort(arr, left, right, tmp);
free(tmp);
}
void MergSortNotR(int arr[], int left, int right)
{
(void)left;
int *tmp = (int*)malloc(sizeof(arr[0]) * right);
if(tmp == NULL)
{
perror("malloc");
//assert(tmp);
return;
}
int gap = 1;
while(gap < right)
{
for(int i = 0; i < right; i += 2 * gap)
{
int begin = i;
int mid = begin + gap;
int end = mid + gap;
if(mid >= right)
mid = right;
if(end >= right)
end = right;
MergData(arr, begin, mid, end, tmp);
}
memcpy(arr, tmp, sizeof(arr[0]) * right);
gap *= 2;
}
free(tmp);
}
int main()
{
int arr[] = {2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 11, 14, 13, 15, 12};
PrintArr(arr, (sizeof(arr)/sizeof(arr[0])));
//BoubbleSort(arr, (sizeof(arr)/sizeof(arr[0])));
//SelectSort(arr, (sizeof(arr)/sizeof(arr[0])));
//InsertSort(arr, (sizeof(arr)/sizeof(arr[0])));
//ShellSort(arr, (sizeof(arr)/sizeof(arr[0])));
//QuickSort(arr, 0, (sizeof(arr)/sizeof(arr[0])));
//QuickSortNotR(arr, 0, (sizeof(arr)/sizeof(arr[0])));
//MergSort(arr, 0, sizeof(arr) / sizeof(arr[0]));
MergSortNotR(arr, 0, sizeof(arr) / sizeof(arr[0]));
PrintArr(arr, (sizeof(arr)/sizeof(arr[0])));
return 0;
}
排序
最新推荐文章于 2022-06-04 00:18:54 发布