选择,冒泡,快速,希尔,堆排序--C语言

排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的序列。重新排列成有序的序列。

排序的时间复杂度,空间复杂度,还有稳定性往往是选取的目标。时间复杂度,空间复杂度越低越好,稳定性越稳定越好。时间,空间即消耗的越小越好。稳定性则是看数据是否有跳跃交换,跳跃的话就不稳定,不跳跃(相邻交换)就稳定。

常见的排序算法有八种。现就这八种展开描述:

1.堆排序

/*

1.建立大根堆:把所有数据按照完全二叉树建立堆,规则如下: 每个根结点下标为i,左孩子下标为(2*i+1),右孩子下标为        (2*+2)。大根堆就是每个子树的根结点数值都要大于孩子结点数值。所以要从最后一个数开始比较,把最大的数放到  所有树的根结点。

2.把大根堆的根结点的值和当前最后子结点的值进行交换,即把大的数据放到后面,即这个数视为有序,除去当前数据序列。再 次建立大根堆,再次交换,依次进行。直到只剩根结点。

//这里使用封装函数,思路更清晰

//时间复杂度为O(nlogn), 空间复杂度O(1),不稳定
*/

void Swap(int* a,int* b)//交换函数
{
    int c = *a;
    *a = *b;
    *b = c;
}
void OneAdjust(int* arr,int len,int root)///排序,使树有序,即根结点大于子结点
{
    int tmp = arr[root];
    int left = 2 * root + 1;
    int right = 2 * root + 2;
    int max;
    while(left < len)//左孩子下标要小于数据长度
    {
        max = left;
        if(right < len && arr[left] < arr[right])//右孩子下标小于数据长度,且做孩子的值小于右孩子的值
        {
            max = right;
        }
        if(tmp > arr[max])
        {
            break;
        }
        arr[root] = arr[max];
        root = max;
        left = 2 * root + 1;
        right = 2 * root + 2;
    }
    arr[root] = tmp;
}
void GreatHeap(int* arr,int len)//建立大根堆
{
    int root = (len - 1 - 1) / 2;

    for(;root >= 0;root--)
    {
        OneAdjust(arr,len,root);
    }
}
void HeapSort(int* arr,int len)
{
    GreatHeap(arr,len);
    for(int i = 0;i < len - 1;i++)
    {
        Swap(&arr[0],&arr[len-1-i]);//交换值
        OneAdjust(arr,len-1-i,0);
    }
}


#define N 10
int main()
{
    srand((unsigned int)time(NULL));//随机函数,生成随机数组
    int arr[N] = {0};
    int i = 0;
    for(;i < N;i++)
    {
        arr[i] = rand() % 100;//取100以内的值
        printf("%5d",arr[i]);
    }
    printf("\n");

    printf("排序如下:\n");
    HeapSort(arr,N);

    for(i = 0;i < N;i++)
    {
        printf("%5d",arr[i]);
    }
    printf("\n");
}

2.快速排序:

/*
1.找数据序列一个数据为基准,设立两个下标i,j.分别放在数据序列的头和尾.j从后往前走,找比基准小的第一个数,并把这个数据放到i的位置。然后i从前往后走,找比基准大的第一个数,放到j的位置。然后依次进行。直到ij相遇。以这个数为中间数,把数据序列分开,前面的数列为比次数小的数,后面的数为比此数列大的数。

2.可以用递归,把两边的数列分别依次排序,调整成有 序数列。思想简单,但操作数过大,会造成内存溢出。

3.也可以用栈的方法求解。

// 时间复杂度(O(nlogn)) 空间复杂度O(1) 不稳定
*/
 

int    Quick(int* arr,int start,int end)//先遍历一遍,划分数据
{
    int tmp = arr[start];
    while(start < end)
    {
         while(start < end)
         {
             if(arr[end] < tmp) break;
             end--;
         }
         arr[start] = arr[end];
         while(start < end)
         {
             if(arr[start] > tmp)break;
             start++;
         }
         arr[end] = arr[start];
    }
    arr[start] = tmp;
    return start;
}
void OneQuick(int* arr,int start,int end)//递归遍历mod两边的数据
{
    
    int mod = Quick(arr,start,end);
    if(mod - start > 1)
    {
        OneQuick(arr,start,mod -1);
    }
    if(end - mod > 1)
    {
        OneQuick(arr,mod+1,end);
    }
}
void QuickSort(int* arr,int len)
{
    OneQuick(arr,0,len-1);
}

3.直接插入:

/*
        一列数据,定义两个下标 i 和 j,i的下标为数据序列第二个数,j的下标为数据i的前一个。因为我们可以把一个数据看成有序,两个及以上的数据序无序,所以把i定义为第二个数的下标,并且我们把i下标之前的数据看成有序,把i插入i之前的序列。直到插完结束。

//时间复杂度O(n^2),空间复杂度O(1),稳定
*/
void InsertSort(int* arr,int len)
{
    int i,j;
    for(i = 1;i < len;i++)
    {
        int tmp = arr[i];//存arr[i]到tmp
        for(j = i-1;j >= 0;j--)
        {
            if(arr[j] < tmp)
            {
                break;
            }
            arr[j+1] = arr[j];//arr[j] > tmp就执行
        }
        arr[j+1] = tmp;
    }
}

4.希尔排序:

/*
其实也是插入排序,在插入排序的基础上分组,先对每组的数据进行排序,使每组数据有序,然后将有序的组进行排序,分组也不固定,视情况而定。一般就5组,3组,1组。以这样的顺序。依次使整个数据序列趋于有序。最终使整个数据序列有序。

//时间复杂度O(n^1.3)~O(n^1.5),空间O(1),不稳定
*/
void ShellGroup(int* arr,int len,int group)
{
    int i = 0;
    int j = 0;
    for(i = group;i < len;i++)
    {
        int tmp = arr[i];
        for(j = i-group;j >= 0;j -= group)
        {
            if(arr[j] < tmp)
            {
                break;
            }
            arr[j+group] = arr[j];
        }
        arr[j+group] = tmp;
    }
}
void ShellSort(int* arr,int len)
{
    int str[] = {5,3,1};
    for(int i = 0;i < sizeof(str)/sizeof(str[0]);i++)
    {
        ShellGroup(arr,len,str[i]);
    }
}

5.选择排序:

/*
一列数据,把最小的放在第一个,第二个数与剩下的数进行比较 再把最小的放在前面。依次进行,直到最后一个数,排列完毕。

//时间复杂度O(n^2),空间复杂度O(1),不稳定
*/
void SelectSort(int*arr,int len)
{
    int i = 0;
    int j = 0;
    int tmp;
    for(int i = 0;i < len-1;i++)
    {
        int min = arr[i];
        int j;
        for(j = i+1;j < len;j++)
        {
            if(arr[j] < min)
            {
                min = arr[j];
                tmp = j;
            }
        }
        if(min != arr[i])
        {
            Swap(&arr[i],&arr[tmp]);//交换
        }
    }
}

6.冒泡排序:

/*
挨个比较,小的放前,大的排后。一个数视为有序一趟只能确定一个数,所以n个数需要(n-1)趟。

时间复杂度为O(n^2),空间复杂度为O(1),稳定
*/
void BubbleSort(int* arr,int len)
{
    for(int i = 0;i < len-1;i++)//n-1趟
    {
        for(int j = 0;j < len-1-i;j++)//每走一趟,多一个数据有序,即有序序列数增多,suoyi
        {
            if(arr[j] > arr[j+1])
            {
                Swap(&arr[j],&arr[j+1]);//交换
            }
        }
    }
}

基数排序见链接:基数排序_Victor_psl的博客-CSDN博客

归并排序见链接:归并排序--C语言_Victor_psl的博客-CSDN博客

        后面几个方法没写主函数,其实方法类似堆排序,在主函数里面调用即可。交换也是函数调用,在堆排序里。

      如有问题,敬请指出!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值