//冒泡,快排
//插排,希尔排序
//选择排序,堆排序
//归并排序
//1.插入排序
//默认当前元素之前的所有元素有序
//把当前元素插入到之前元素中的合适位置
void insert_sort(int a[], int n)
{
int i, j, k;
for(i = 0; i < n; i++) {
for(j = i-1, k = a[i]; j >= 0 && k < a[j]; j--) {//把该元素插入到合适的位置,其他元素后移
//从当前元素的上一个元素开始查找
//k < a[j] 说明a[j+1]无用
a[j+1] = a[j];
a[j] = k;//完成了和上一个元素的交换
}
}
}
//2.希尔(Shell)排序
//设定步长后的插入排序
void shell(int a[], int n)
{
int gap, i, j, k;
for(gap = n/2; gap > 0; gap /= 2) {//设置排序的步长,步长gap每次减半,直到减到1
for(i = gap; i < n; i++) {//定位到每一个元素
for(j = i-gap, k = a[i]; (j >= 0) && (k < a[j]); j -= gap ) {
//比较相距gap远的两个元素的大小,根据排序方向决定如何调换
a[j+gap] = a[j];
a[j] = k;
}
}
}
}
//3.二分插入法
void HalfInsert_Sort(int a[], int len)
{
int i, j,temp;
int low, high, mid;
for (i=1; i<len; i++)
{
temp = a[i];/* 保存但前元素 */
low = 0;
high = i-1;
while (low <= high) /* 在a[low...high]中折半查找有序插入的位置 */
{
mid = (low + high) / 2; /* 找到中间元素 */
if (a[mid] > temp) /* 如果中间元素比但前元素大,当前元素要插入到中间元素的左侧 */
{
high = mid-1;
}
else /* 如果中间元素比当前元素小,但前元素要插入到中间元素的右侧 */
{
low = mid+1;
}
} /* 找到当前元素的位置,在low和high之间 */
for (j=i-1; j>high; j--)/* 元素后移 */
{
a[j+1] = a[j];
}
a[high+1] = temp; /* 插入 */
}
}
//4.选择排序法
void select(int a[], int n)
{
int i, j, mins;
for(i = 0; i < n; i++) {
mins = i;
for(j = i; j < n; j++) {
if(a[mins] > a[j])
mins = j;
}
if(mins != i) {//如果mins发生了改变
int t;
t = a[mins];
a[mins] = a[i];
a[i] = t;
}
}
}
//5.堆排序
//注意当数组的下标从1开始时,左孩子节点下标为2*i,右孩子节点为2*i+1
//当数组的下标从0开始时,左孩子节点下标为2*(i+1) -1,右孩子节点为2*(i+1)+1 -1
void Heap_adjust(int a[], int s, int m)//s和m分别是更改大顶堆的起始下标和终点下标
{
int temp = a[s];//从始至终没有发生改变,其作用就是记住s节点的值
for(int j = 2*(s+1)-1; j <= m; j = 2*(j+1)-1) {//沿关键字较大的孩子节点向下寻找
//当数组的下标从0开始时,左孩子节点下标为2*(i+1) -1,右孩子节点为2*(i+1)+1 -1
if(j < m && a[j] < a[j+1])//注意j<m而不是j<=m;当j=m时,j++超出终点下标,会出现bug
j++;//j为关键字较大的孩子节点的坐标
if(temp >= a[j])
break;
a[s] = a[j];//如果没有从循环中退出则说明temp<a[j];即目前为止最大的节点是a[j];
s = j;//s是双亲节点坐标
}
//从循环中退出有两种方式->1,没有孩子节点;2,temp>=a[j];
a[s] = temp;
}
void Heap_sort(int a[], int n)
{
//堆是一个完全二叉树,完全二叉树的线性表示就是数组
for(int i = n/2-1; i >= 0; i--) { //从最后一个非终端节点开始,构造一个大顶堆
Heap_adjust(a, i, n-1);//从非终端节点开始逐个向前调整完全二叉树
}
for(int i = n-1; i > 0; i--) { //取出堆顶记录
int t = a[i]; a[i] = a[0]; a[0] = t; //将a[0]放到最后
Heap_adjust(a, 0, i-1);//调整0 1 2 ... i-1的大顶堆
}
}
//6.冒泡排序法
void buble_sort(int a[], int n)
{
int t; int flag = 1;
//flag是判断序列是否有序的标识,只有当flag为1时说明数列无序
//例:2 1 3 4 5
//进入第一次循环flag = 0; 并把2 和 1交换了位置,flag又变成了1
//第二次进入循环,flag为0,没有发生交换,则说明数列有序,以后不需要
//判断并交换了
for(int i = 0; i < n-1 && flag == 1; i++) {
flag = 0;
//从最后面向前比较,每当i向前走了一步,则说明这个位置的值已经确定了
for(int j = n-2; j >= i; j--) {
if(a[j] > a[j+1]) {
t = a[j+1];
a[j+1] = a[j];
a[j] = t;
flag = 1;
}
}
}
}
//7.快速排序
void qsort(int a[], int left, int right)
{
if(left >= right)
return;
int i, j, key;
i = left, j = right, key = a[left];
while(i < j) {
while(i < j && key <= a[j])
j--;
a[i] = a[j];
while(i < j && key >= a[i])
i++;
a[j] = a[i];
}
a[i] = key;
qsort(a, left, i-1);
qsort(a, i+1, right);
}
//归并排序->递归版
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for(j = m+1, k = i; i <= m && j <= n; k++) {//将SR中的记录由小到大归并入TR
if(SR[i] < SR[j]) TR[k] = SR[i++];
else TR[k] = SR[j++];
}
if(i <= m) {//将剩余的SR[i...m]复制到TR
for(l = 0; l <= m-i; l++)
TR[k+l] = SR[i+l];
}
if(j <= n) {//将剩余的SR[j...n]复制到TR
for(l = 0; l <= n-j; l++)
TR[k+l] = SR[j+l];
}
}
void Msort(int SR[], int TR1[], int s, int t)
{
int m;
int TR2[6];
if(s == t)
TR1[s] = SR[s];
else {
m = (s+t)/2;//将SR平分为SR[s...m]和SR[m+1...t]
Msort(SR, TR2, s, m);//递归将SR[s...m]归并为有序的TR2[s...m]
Msort(SR, TR2, m+1, t);//递归将SR[m+1...t]归并为有序的TR2[m+1...t]
Merge(TR2, TR1, s, m, t);//将TR2[s...m]和TR2[m+1...t]归并到TR1[s...t]
}
}
//归并排序->非递归版
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k, l;
for(j = m+1, k = i; i <= m && j <= n; k++) {//将SR中的记录由小到大归并入TR
if(SR[i] < SR[j]) TR[k] = SR[i++];
else TR[k] = SR[j++];
}
if(i <= m) {//将剩余的SR[i...m]复制到TR
for(l = 0; l <= m-i; l++)
TR[k+l] = SR[i+l];
}
if(j <= n) {//将剩余的SR[j...n]复制到TR
for(l = 0; l <= n-j; l++)
TR[k+l] = SR[j+l];
}
}
void MergePass(int SR[], int TR[], int s, int n)
{
int i = 1;
int j;
while(i <= n-2*s+1) {
Merge(SR, TR, i, i+s-1, i+2*s-1); //两两归并
i = i+2*s;
}
if(i < n-s+1)//归并最后两个序列
Merge(SR, TR, i, i+s-1, n);
else//若最后只剩下单个子序列
for(j = i; j <= n; j++)
TR[j] = SR[j];
}
void MergeSort2(int a[], int n)
{
int *TR = (int *)malloc(n * sizeof(int));
int k = 1;
while(k < n) {
MergePass(a, TR, k, n);
k *= 2; //子序列长度加倍
MergePass(TR, a, k, n);
k *= 2; //子序列长度加倍
}
}