#include <iostream>
using namespace std;
void print(int a[], int len)
{
for(int i = 0; i < len; i++)
cout << a[i] << " ";
cout << endl;
}
void swap(int &a, int &b)
{
if( a > b)
{
int t = a;
a = b;
b = t;
}
}
void bubble_sort(int a[], int len)
{
//冒泡排序
int exchange = 0; //设置标记
for(int i = 0; i < len - 1; i++) //总共有 n-1 次排序
{
exchange = 0; //每次把标记置 0
for(int j = len - 2; j >= i; j--) //从后往前比较
{
if(a[j] > a[j+1]) //比较大小,交换数据
{
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
exchange = 1; //发生数据交换,标记置1
}
}
if(exchange != 1) //标记不为1,跳过这次循环
break;
}
}
void select_sort(int a[], int len)
{
//简单选择排序,每次找到最小的那个数和第一个数交换位置
int i, j, tmp, min;
for(i = 0; i < len -1 ;i++) // n-1 次 循环
{
tmp = a[i]; //记录每次第一个元素的值和下标
min = i;
for(j = i+1; j < len; j++)
{
if(a[j] < tmp) //如果当前位置的值小于第一个元素的值
{
tmp = a[j]; //把当前元素的值和下标记录下来
min = j;
}
}
if(min != i) //如果flag标记发生变化,表示有元素的值比第一个数小
{
a[min] = a[i]; //交换两个数的值
a[i] = tmp;
}
}
}
void insert_sort(int a[], int len)
{
//直接插入排序:把第一个数当成一个有序数组,后面的数一个一个有序的插入的数组中
int i, j, tmp;
for(i = 1; i < len; i++)
{
tmp = a[i]; //tmp用来记录要插入的数的值
//满足条件,往后挪。当 tmp > a[j] 小,tmp 放在 a[j] 后面
for(j = i-1; j >= 0 && tmp < a[j]; j--)
a[j+1] = a[j];
a[j+1] = tmp;
}
}
void shell_sort(int a[], int len)
{
int d = len;
while(d > 1)
{
d = (d + 1)/2; //设置增量
for(int i = 0; i < len -d; i++)
{
if(a[i] > a[i+d]) //交换相隔距离 d 的两个数的值
{
int tmp = a[i];
a[i] = a[i+d];
a[i+d] = tmp;
}
}
}
}
void heap_adjust(int a[], int len, int index)
{
int left = 2*index + 1; //父节点左孩子下标
int right = 2*index + 2; //父节点有孩子下标
int maxindex = index; //令最大值的下标为当前父节点下标
if(left < len && a[left] > a[maxindex]) //在数组范围内且左孩子的值大于父节点的值
maxindex = left; //最大值下标变为左孩子下标
if(right < len && a[right] > a[maxindex]) //在数组范围内且右孩子的值大于父节点的值
maxindex = right; //最大值下标变为右孩子下标
if(maxindex != index) //当最大值下标更新
{
swap(a[maxindex], a[index]); //交换最大值下标对应的值和父节点的值
heap_adjust(a, len, maxindex); //递归调整其他不满足堆性质的部分
}
}
void heap_sort(int a[], int len)
{
int i; //最后一个非叶子节点的下标为 len/2 -1
for(i = len/2 -1; i >= 0; i--) //对每一个父节点进行调整,使堆变成大顶堆(从最后一个父节点开始) 非叶子结点即父节点
{
heap_adjust(a, len, i); // i 为当前父节点下标
}
for(i = len -1; i > 0; i--) //从后往前,保存最大的数
{
swap(a[0], a[i]); //把经过调整的大顶堆的最大值和最后一个元素互换位置,放到数组末尾
heap_adjust(a, i, 0); //将剩下的部分继续进行堆排序
}
}
void merge(int a[], int begin, int middle, int end)
{
int i, j, k, leftlen, rightlen;
leftlen = middle - begin + 1; //左区间元素个数
rightlen = end - middle; //右区间元素个数
int *L = new int(leftlen); //申请两个数组用来分别存放 左区间 和 右区间 的元素
int *R = new int(rightlen);
for(i = 0, k = begin; i < leftlen; i++, k++) //对 数组 L 进行赋值
{
L[i] = a[k];
}
for(i = 0, k = middle + 1; i < rightlen; i++, k++) //对 数组 R 进行赋值
{
R[i] = a[k];
}
for(k = begin, i = 0, j = 0; i < leftlen && j < rightlen; k++) //对原数组进行重新排序
{
if(L[i] < R[j]) //左区间当前下标的值小于右区间的值
{
a[k] = L[i]; //数组当前下标元素的值为左区间的值
i++; //左区间下标加1
}
else //反之
{
a[k] = R[j]; //数组当前下标元素的值为右区间的值
j++; //右区间下标加1
}
}
if(i < leftlen) //这两个 if 语句 是将 左区间 和 右区间 归并剩下的数据 放到数组的最后面
{
for(j = i; j < leftlen; j++, k++) // j = i 属于习惯问题 可以写成 for (; i < n1; i++, k++)
{
a[k] = L[j];
}
}
if(j < rightlen)
{
for(i = j; i < rightlen; i++, k++) // i = j 属于习惯问题 可以写成 for (; j < n2; j++, k++)
{
a[k] = R[i];
}
}
delete [] L;
delete [] R;
}
void merge_sort(int a[], int begin, int end)
{
if(begin < end)
{
int middle = (begin + end) / 2; //定义分界点,将数组分为两部分
merge_sort(a, begin, middle); //对左区间 [begin, middle] 递归做归并排序
merge_sort(a, middle + 1, end); //对右区间 [middle + 1, end] 递归做归并排序
merge(a, begin, middle, end); //组合,将两个有序的区块合并成一个有序的区块
}
}
void quick_sort(int a[], int begin, int end)
{
if(begin < end)
{
int pivot = a[begin]; //将数组第一个数作为比较关键字,保存下来
int i = begin; //从前往后
int j = end; //从后往前
while(i < j)
{
while(i < j && a[j] >= pivot) // i < j 且 a[j] 大于等于 关键字 时
j--; // j--, 下标向前挪一位
if(i < j && a[j] < pivot) // i < j 且 a[j] 小于 关键字 时
a[i++] = a[j]; // 令 a[i] = a[j] a++ 下标向后挪一位
while(i < j && a[i] <= pivot) // i < j 且 a[i] 小于等于 关键字 时
i++; // i++, 下标向后挪一位
if(i < j && a[i] > pivot) // i < j 且 a[i] 大于 关键字 时
a[j--] = a[i]; // 令 a[j] = a[i] j-- 下标向前挪一位
}
a[i] = pivot;
quick_sort(a, begin, i - 1);
quick_sort(a, i+1, end);
}
}
int main()
{
int a[] = {7,1,3,2,5,6,4,9,8};
int len = sizeof(a)/sizeof(a[0]);
cout << "排序前" << endl;
print(a, len);
// 冒泡排序:两辆比较关键字,反序则交换
// cout << "冒泡排序" << endl;
// bubble_sort(a, len);
// print(a, len);
// 简单选择排序:通过(n - i)次关键字间的比较, 从(n - i - 1)个记录中选择关键字最小的记录,并和第 i 个记录交换位置
// cout << "选择排序" << endl;
// select_sort(a, len);
// print(a, len);
// 直接插入排序:将第一个数视为有序数组,把后面每一个数都有序插入到数组中,使整个序列有序
// cout << "直接插入排序" << endl;
// insert_sort(a, len);
// print(a, len);
// 希尔排序:把相距某一个增量 d( d = len; d = (d+1)/ 2;) 的记录组成子序列,然后在子序列内进行直接插入排序,再对全体记录进行一次直接插入排序
// cout << "Shell排序" << endl;
// shell_sort(a, len);
// print(a, len);
// 堆排序:将待排序的序列构造成一个大顶堆(完全二叉树,根节点最大),将根节点和堆末尾元素交换,然后将剩余的元素重新构造堆,再选出最大值,反复执行
// cout << "堆排序" << endl;
// heap_sort(a, len);
// print(a, len);
// 将序列拆分成多个单个数组,再两两归并,得到有序的多个子序列,反复执行直至只有一个有序的序列为止
// cout << "归并排序" << endl;
// merge_sort(a, 0, len -1);
// print(a, len);
//快速排序:在一堆待排序记录中选择关键字,将序列分为两组,一组比关键字都小,另一组比关键字都大,递归执行,可得到一个有序序列
cout << "快速排序" << endl;
quick_sort(a, 0, len - 1);
print(a, len);
return 0;
}