排序

  1. 直接插入排序(类似于打牌)
    1.1:解决的关键问题:
    1.1.1:构造初始有序序列
    1.1.2:查找待插入记录的插入位置
void InsertSort(int a[], int n) {
    //i从2开始,i默认1位有序,就此分为有序区和无序区
    for (int i = 2; i <= n; i++)
    {
       a[0] = a[i];//设置哨兵好处:1:保存a[i]的值,避免移动过程中被覆盖
       //2:充当哨兵,做循环的条件
       int j;
       for ( j = i-1; a[j] > a[0]; j--)
       {
           //出现的错误:弄成了j++,而应该是j+1,不然就成了死循环
           a[j+1] = a[j];//把已经比较过的值进行右移
           //if (a[i] > a[j])
           //{

           //    break;//找a[i]插入的位置
           }   
       a[j+1] = a[0];
    }
}

1.2:二分插入排序

int BinarySearchIndex(int a[], int left, int right, int x)
{

    while (left <= right)
    {
        int mid = (left + right) / 2;
        if (a[mid] > x)
        {
            right = mid - 1;
        }//就算是等于往后面插入更加优化
        else
        {
            left = mid + 1;
        }
    }
    return left;

}
void InsertSortBinarySearch(int a[], int n) {
    //i从2开始,i默认1位有序,就此分为有序区和无序区
    for (int i = 2; i <= n; i++)
    {
        int temp = a[i];
        //没有借鉴直接插入排序的经验,保存好变量值,移动过程中会覆盖值
        int index = BinarySearchIndex(a, 1, i - 1, a[i]);
        for (int j = i - 1; j >= index; j--)
        {
            //不要习惯性的用j++,否则不能跳出循环
            a[j+1] = a[j];
        }
        a[index] = temp;
    }
}

1.3:希尔排序:
1.3.1:改进的点:
1.3.1.1:基本有序的情况下,插入排序效率高
1.3.1.2:数量少的情况下效率高

void ShellSort(int a[], int n) {
    //外层是个衡量指标,每次跨度距离
    for (int d = n / 2; d >= 1; d /= 2) {//以增量d为直接插入排序
        for (int i = d+1; i <= n; i += d)//前面的d项默认为有序
        { 
            a[0] = a[i];//只是暂存a[i]的值,不起到哨兵的作用,因为循环推出的条件是j<0||a[0]>=a[j]
            int j;
            for (j = i - d; j > 0 && a[j] > a[0]; j -= d)
            {
                a[j + d] = a[j];
            }
            a[j + d] = a[0];

        }
       
 }
}

2:交换排序
2.1:冒泡排序

void BubbleSort(int a[], int n)
{
    for (int i = 0; i < n - 1; i++)//只需要进行n-1趟
    {
        int flag = 0;
        for (int j = 1; j < n - i; j++)
        {
            if (a[j] < a[j - 1])
            {
                swap(a[j], a[j - 1]);
                flag = 1;
            }
        }
        if (flag == 0)break;
    }
}

2.2:快速排序:对冒泡排序的改进,冒只能一次移动一个,而快排是从两端向中间进行,移动的距离比较远。
2.2.1:解决的关键问题:
2.2.1.1:如何进行一次划分

//5:快速排序
int Partition(int r[], int first, int end)
{
    int i = first, j = end;
    while (i < j)
    {
        //其实这里应该不用临时变量储存,因为轴值就存储在a[i]或者a[j]中
        while (i<j&&a[i] <= a[j]) j--;
        if (i < j) {
             swap(a[i], a[j]);
             i++;
        }       
        while (i < j&&a[i]<=a[j])  i++;
        if (i < j){ 
            swap(a[i], a[j]);
            j--;
        }
    
       
    }
     return i;
    
}
//5.1:快速排序的递归写法
void QuickSort(int a[], int first, int end)
{
    if (first < end) {//如果区间长度大于1,则继续划分,否则结束
        int pivot = Partition(a, first, end);
        QuickSort(a, first, pivot - 1);//递归地往两边划分
        QuickSort(a, pivot + 1,end );
    }
}

3:选择排序

//2:选择排序
void SelectSort(int a[], int n) {
    for (int i = 0; i < n - 1; i++)//只需要n-1趟
    {
        int k=i;
        //从剩余的元素中找出最小的元素
        for (int j = i; j < n; j++)
        {
            if (a[i] > a[j])k = j;
        }
        if (k != i)swap(a[i], a[k]);
    }
}

3.1;堆排序:改进(减少关键码的比较次数)
3.1.1:筛选:

void sift(int r[], int k, int m)
{//要筛选结点的编号为k,堆中最后一个结点的编号为m 
    int i, j;
    i = k;  j = 2 * i;//根据树的节点的特点
    while (j <= m)           //筛选还没有进行到叶子,即存在孩子节点
    {
        if (j < m && r[j] < r[j + 1]) j++;  //左右孩子中取较大者
        if (r[i] > r[j]) break;
        else { swap(a[i], a[j]);   i = j;   j = 2 * i; }
    }
}

3.1.2:
建堆的过程:此序列是按完全二叉树的顺序存储,所以建堆的过程就是反复筛选的过程;
3.1.3:处理堆顶

void  HeapSort(int  r[], int n)
{
    int i;
    for (i = n / 2; i >= 1; i--)      //初建堆
        sift(r, i, n);
    for (i = 1; i > n; i++)
    {
        swap(r[1],r[n - i + 1]); //移走堆顶           
        sift(r, 1, n - i);               //重建堆
    }
}

4:归并排序
4.1:二路归并排序解决的关键问题:
4.1.1:如何构造初始有序序列?看成长度为1的有序序列
4.1.2:一次归并:将相邻的有序序列归并成一个有序序列?

void Merge(int r[], int r1[], int s, int m, int t)
{
    int i, j, k;
    i = s;  j = m + 1;   k = s;
    while (i <= m && j <= t)
    {
        if (r[i] <= r[j])  r1[k++] = r[i++];
        else  r1[k++] = r[j++];
    }
    if (i <= m)  while (i <= m)              //收尾处理
        r1[k++] = r[i++];    //前一个子序列
    else  while (j <= t)
        r1[k++] = r[j++];             //后一个子序列
}

4.1.3:怎么完成一趟归并?主要是看i与n以及h长度之间关系

void  MergePass(int  r[], int  r1[], int  n, int  h)
{
    int i,k;
    i = 1;
    while (i<=n-2*h + 1)                          //情况1:还可以继续进行归并
    {
        Merge(r, r1, i, i + h - 1, i + 2 * h - 1);
        i += 2 * h;
    }
    if (i<=n - h + 1) Merge(r, r1, i, i + h - 1, n);   //情况2:剩最后两个序列,完成后退出
    else for (k = i; k <= n; k++)           //情况3:最后一个有序表,直接进行复制
        r1[k] = r[k];
}

4.1.4:怎么控制归并的结束?

//步骤3:控制二路归并的结束
void  MergeSort(int r[], int r1[], int n)
{
    int h;
    h = 1;
    while (h < n)
    {
        MergePass(r, r1, n, h);
        h = 2 * h;
        //弄偶数次的话保证倒回到数组r中
        MergePass(r1, r, n, h);
        h = 2 * h;
    }
}

4.2:递归实现(理解栈的实现过程):

//递归实现
void MergeSort2(int r[], int r1[], int s, int t)
{
    int m;
    if (s == t) r1[s] = r[s];                        //递归出口:只有一个元素时
    else {
        m = (s + t) / 2;
        MergeSort2(r, r1, s, m);           //归并排序前半个子序列
        MergeSort2(r, r1, m + 1, t);       //归并排序后半个子序列
        Merge(r1, r, s, m, t);          // 将两个已排序的子序列归并
    }
}

5:桶排序和基数排序的思想弄懂了,但是代码没调通。
6:比较:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值