排序

//冒泡,快排
//插排,希尔排序
//选择排序,堆排序
//归并排序



//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; //子序列长度加倍
    }
}





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值