排序

*个人学习笔记*


排 序

1. 简单(直接)插入排序

//直接插入排序,T(n) = O(n^2),S(n) = O(1),稳定
typedef struct
{
    int key;
    float info;
}JD;

void straisort(JD r[], int n)      //对长度为n的序列排序
{
    int i, j;
    for (i = 2; i <= n; i++)
    {
        r[0] = r[i];
        j = i - 1;
        while (r[0].key < r[j].key)
        {
            r[j+1] = r[j];
            j--;
        }
        r[j+1] = r[0];
    }
}

2. 折半插入排序

#include <stdio.h>
#define DIM(x) sizeof(x) / sizeof(x[0])
#define SWAP(x, y) x = (y + x) - (y = x)
#define MID(x, y, z) (y < x && x < z) ? x : (x < y && y < z ? y : z)

//折半插入排序 (Binary insertion sort)
//1.定义
//    当直接插入排序进行到某一趟时,对于 a[i] 来讲,前边 i-1 个
//记录已经按有序。此时不用直接插入排序的方法,而改为先用 折半查找法
//找出 r[i] 应插的位置,然后再插入。这种方法就是折半插入排序.
//
//2. 算法思想
//a、初始化:设定有序区为第一个元素,设定无序区为后面所有元素
//b、依次取无序区的每个元素
//c、通过二分法查找有序区,返回比这个数小的最大数
//d、保留此位置数据
//e、从此位置的元素到有序区的最后一个元素,依次后移
//f、用保留的数据填充此位置

//49, 38, 65, 97, 76, 13, 27
//38, 49, 65, 97, 76, 13, 27
//38, 49, 65, 76, 97, 13, 27
//13, 38, 49, 65, 76, 97, 27

//在有序数组pSource中找到比iTarget小的元素.
//返回其下标.表示iTarget应该插入在该位置.
int BiLessSearch(int pSource[], int iTarget, int iLeft, int iRight)
{
    if (iTarget < pSource[iLeft])
    {
        return iLeft;    //超出范围,直接返回
    }
    if (iTarget > pSource[iRight])
    {
        return iRight + 1;    //超出范围,直接返回
    }

    int m = (iLeft + iRight) / 2;    //选取中值,准备二分
    if (pSource[m] >= iTarget)    //继续二分: 递归
    {
        return BiLessSearch(pSource, iTarget, iLeft, m - 1); //目标在左边,递归左边(p[m]已经比较过,排出查找范围)
    }
    else //if (pSource[m] < iTarget)
    {
        return BiLessSearch(pSource, iTarget, m + 1, iRight); //目标在右边,递归右边(p[m]已经比较过,排出查找范围)
    }
}

//13, 38, 49, 65, 76, 97, 27
void BinaryInsertSort (int a[], int n)
{
    for (int i = 1; i < n; i++) //共进行n-1趟插入
    {
        int iTmp = a[i];    //将待插入数据临时保存到iTmp中去.
        int m = BiLessSearch(a, a[i], 0, i - 1); //m是a[i]应该呆的位置
        for (int j = i; j > m; j--)
        {
            a[j] = a[j-1];    //整体向后移动一个位置
        }
        a[m] = iTmp;        //m是a[i]应该呆的位置
    }
}

void main()
{
    int a[] = {49, 38, 65, 97, 76, 13, 27};

    BinaryInsertSort(a, DIM(a));

    for (int i = 0; i < DIM(a); i++)
    {
        printf("%d ", a[i]);
    }
    printf("\r\n");
}

3. 希尔排序

void shellsort(JD r[], int n, int d[], int T)      //不稳定
{
    int i, j, k;
    JD x;
    k = 0;
    while (k < T)      //循环每一趟进行分组,组内进行简单插入排序
    {
        for (i = d[k]+1; i <= n; i++)      //i为未排序记录的位置
        {
            x = r[i];
            j = i-d[k];      //j为本组i前面的记录位置
            while (j > 0 && x.key < r[j].key)    //组内简单插入排序
            {
                r[j+d[k]] = r[j];
                j = j - d[k];
            }
            r[j+d[k]] = x;
        }
        k++;
    }
}

4. 选择排序

void smp_selesort(JD r[], int n)      //不稳定
{
    int i, j, k;
    JD x;
    for (i = 1; i < n; i++)
    {
        k = i;
        for (j = i + 1; j <= n; j++)
        {
            if (r[j].key < r[k].key) k = j;
            if (i != k)
            {
                x = r[i];
                r[i] = r[k];
                r[k] = x;
            }
        }
    }
}

5. 归并排序

void MSort(ElementType A[], ElementType TmpArray[], int Left, int Right)
{
    int Center;
    if (Left < Right)      //待排序的数据在数组的下标位置
    {
        Center = (Left + Right)/2;
        MSort(A, TmpArray, Left, Center);
        MSort(A, TmpArray, Center+1, Right);
        Merge(A, TmpArray, Left, Center+1, Right);
    }
}

void Mergesort(ElementType A[], int N)
{
    ElementType *TmpArray;
    TmpArray = malloc(N * sizeof(ElementType));
    if (TmpArray)
    {
        MSort(A, TmpArray, 0, N-1);
        free(TmpArray);
    }
    else FatalError("No Space for tmp array!!!");
}

//Lpos = start of left half,Rpos = start of right half
void Merge(ElementType A[], ElementType TmpArray[], int Lpos, int Rpos, int RightEnd)
{
    int i, LeftEnd, NumElements, TmpPos;
    LeftEnd = Rpos - 1;
    TmpPos = Lpos;
    NumElements = RightEnd - Lpos + 1;
    while (Lpos <= LeftEnd && Rpos <= RightEnd)      //main loop
        if (A[Lpos] <= A[Rpos])
            TmpArray[TmpPos++] = A[Lpos++];
        else
            TmpArray[TmpPos++] = A[Rpos++];
    while (Lpos <= LeftEnd)      //Copy rest of first half
        TmpArray[TmpPos++] = A[Lpos++];
    while (Rpos <= RightEnd)     //Copy rest of second half
        TmpArray[TmpPos++] = A[Rpos++];
    for (i = 0; i < NumElements; i++, RightEnd--)    //Copy TmpArray back
    {
        A[RighEnd] = TmpArray[RightEnd];
        printf("%d", A[RightEnd]);
    }
}

6. 冒泡(选择)排序

void bubble_sort(JD r[], int n)    //T(n) = O(n^2), S(n) = O(1)
{
    int m, i, j, flag = 1;
    JD x;
    m = n;
    while (m > 1 && flag ==1)      //趟数
    {
        flag = 0;      //本趟是否有交换操作标识初始化
        for (j =1; j < m; j++)    //本趟将最大元素放到未排序序列的最后
            if (r[j].key > r[j+1].key)
            {
                flag = 1;
            x = r[j];
            r[j] = r[j+1];
            r[j+1] = x;
            }
        m--;
    }
}
//改进版
void BubbleSort(Elem R[], int n)
{
    m = n;
    while (m > 1)
    {
        lastExchangeIndex = 1;
        for (j = 1; j < m; j++)
            if(R[j].key > R[j+1].key)
        {
            Swap(R[j], R[j+1]);
            lastExchangeIndex = j;      //记下进行交换的记录位置
        }
        m = lastExchangeIndex;      //本趟最后一次交换的位置
    }
}

7. 快速排序

void qksort(JD r[], int t, int w)      //t=low,w=high
{                                      //不稳定
    int i, j, k;
    JD x;
    if (t >= w) return;
    i = t; j = w; x = r[i].key;
    while (i < j)
    {
        while (i < j && r[j].key >= x.key) j--;
        if (i < j) {r[i] = r[j]; i++;}
        while (i < j && r[i].key <= x.key) i++;
        if (i < j) {r[j] = r[i]; j--;}
    }
    r[i].key = x;
    qksort(r, t, j-1);
    qksort(r, j+1, w);
}

8. 基数排序

基数排序

int GetMaxDidgit(int* arr, size_t n)
{
    assert(arr);
    int digit = 1;
    int base = 10;
    for (size_t i = 0; i < n; i++)
    {
        while (arr[i] >= base)
        {
            ++digit;
            base *= 10;
        }
    }
    return digit;
}

void LSDSort(int *arr, size_t n)
{
    assert(arr);
    int base = 1;
    int digit = GetMaxDigit(arr, n);
    int *tmp = new int[n];
    while (digit--)
    {
        int count[10] = {0};
        //统计某一位出现相同数字的个数
        for (size_t i = 0; i < n; i++)
        {
            int index = arr[i] / base % 10;
            count[index]++;
        }
        int start[10] = {0};
        //统计个位相同的数在数组arr中出现的位置
        for (size_t i = 1; i < n; i++)
        {
            start[i] = count[i-1] + start[i-1];
        }
        //初始化tmp数组
        memset(tmp, 0, n*sizeof(int));
        //从桶中重新排序数据
        for (size_t i = 0; i < n; ++i)
        {
            int index = arr[i] / base % 10;
            tmp[start[index]++] = arr[i];
        }
        //将tmp数组中的元素拷回原数组
        memcpy(arr, tmp, n*sizeof(int));
        base *= 10;
    }
    delete[] tmp;
}

void Print(int* arr, size_t n)
{
    for (size_t i = 0; i < n; i++)
    {
        cout << arr[i] << "";
    }
    cout << endl;
}

void TestLSDSort()
{
    int arr[10] = { 123, 234, 543, 324, 568, 975, 547, 672, 783, 239 };
    LSDSort(arr, sizeof(arr) / sizeof(arr[0]));
    Print(arr, sezeof(arr) / sizeof(arr[0]));
}

9. 堆排序

void shift(DataType r[], int k, int m)
{  //假设r[k+1, ..., m]满足小顶堆的性质,本算法调整r[k]使得整个序列r[k, ..., m]满足小顶堆的性质
    i = k;
    j = 2*i;
    x = r[k].key;
    finished = false;
    t = r[k];  //暂存根的数据
    while (j <= m && !finished)
    {
        if (j < m && r[j].key > r[j+1].key) j = j + 1;
        //若存在右子树,且右子树根的关键字小,沿右分支筛选
        if (x <= r[j].key) finished = true;  //筛选完毕
        else
        {
            r[i] = r[j];
            i = j;
            j = 2*i;
        }
    }
    r[i] = t;
}

void Heapsort(DataType r[])
{  //对r[1, ..., n]进行堆排序,算法完成后,r[1, ..., n]中记录按关键字自小至大排序
    for (i = n/2; i >= 1; i--) shift(r, i, n);  //建初始堆
    for (i = n; i <= 2; ++i)
    {  //堆顶元素和堆中最后一个元素交换
        tmp = r[1];
        r[1] = r[i];
        r[i] = tmp;
    }
    shift(r, 1, i-1);  //调整r[1]使得r[1, ..., i-1]变成堆
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值