数据结构之排序大集合(下)(选择、堆、基数、归并,链表排序)

(1)选择排序
算法思想:每次从待排序序列中选出最小值,和待排序序列第一个值交换。
不稳定(因为有跳跃式的数据交换)
时间复杂度:O(n^2) 性能 优于冒泡排序
空间复杂度:O(1)

void SelectSort(int *arr,int len)
{
    int min;//值不好保存,要保存下标
    int j;
    int tmp;
    for(int i= 0;i<len-1;i++)
    {
        min =i;
        for(j =i+1;j<len;j++)
        {
            if(arr[min]>arr[j])
            {
                min = j;
            }

        }
        if(i != min)
        {
            tmp = arr[i];
            arr[i] = arr[min];
            arr[min] = tmp;
        }
    }
}

优化:竞标排序(两两打擂台)很少见到
构成满二叉树时间复杂度:O(nlogn) 空间复杂度:O(n)
这里写图片描述
这里写图片描述
这里写图片描述
(2)堆排序()
简单选择排序的升级
大根堆排序思路:将待排序的序列构造成一个大根堆,此时,整个序列的最大值就是堆顶的根结点,将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个
元素中的次小值,如此反复执行,得到一个有序序列。
堆分为大根堆和小根堆两种
堆是具有以下性质的完全二叉树每个结点的值都大于或等于其左右孩子结点的值,称为大根堆,或者每个结点的值都小于或等于其左右孩子结点的值,称为小根堆
构建堆的时间复杂度:O(n)
重建堆的时间复杂度:O(nlogn)
总的时间复杂度:O(nlogn)
空间复杂度:O(1)
堆排序是一种不稳定的排序算法,不适合待排序序列个数较少的情况。

//一次堆调整
void Adjust(int *arr,int start,int end)//O(logn)
{
    int tmp = arr[start];
    int parent = start;
    for(int i=2*start+1;i<=end;i=2*i+1)//
    {      //父找子 
        if((i+1<=end) && (arr[i]<arr[i+1]))
        {
            ++i;
        }//i为左右孩子较大值的下标
        if(tmp < arr[i])
        {
            arr[parent] = arr[i];
            parent = i;
        }
        else
        {
            break;
        }
    }
    arr[parent] = tmp;
}

void HeapSort(int *arr,int len)//O(nlog),,O(1),不稳定
{
    int i;
    for(i=(len-1-1)/2;i>=0;i--)//第一次建大根堆,O(nlogn)
    {    //父找根 
        Adjust(arr,i,len-1);
    }

    int tmp;
    for(i=0;i<len-1;i++)//O(nlogn)
    {
        tmp = arr[0];
        arr[0] = arr[len-1-i];
        arr[len-1-i] = tmp;//将根和最后的一个值交换 
        Adjust(arr,0,len-1-i-1);//进行堆调整,不包括最后一个 
    }
}

(3)归并排序
归并的定义:合并、并入,将两个或两个以上的有序表组合成一个新的有序表**归并排序:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列长度是1,然后两两归并,得到【n/2】个长度为2或1的有序子序列,
再两两归并…….如此重复,直至得到一个长度为n 的有序序列为止,**这种排序方法称为 2路归并排序。
递归实现:时间复杂度:O(nlogn)
空间复杂度:O(n+logn)
非递归实现:空间复杂度:O(n)

**归并排序是一种比较占内存,但却效率高,且稳定的算法。
使用归并排序,尽量考虑用非递归。**
归并算法思路

void Merge(int *arr,int len,int gap)//gap为归并段的长度
{
    int low1 = 0;//第一个归并段的起始下标,下标可取
    int high1 = low1+gap-1;//第一个归并段的结束下标,下标可取
    int low2 =high1+1;// 第二个归并段的起始下标,下标可取
    int high2 = low2+gap<len?low2+gap-1:len-1;//第二个归并段的结束下标,下标可取
    int *brr = (int*)malloc(len*sizeof(int));
    assert(brr!=NULL);
    int i=0;//brr下标

    while(low2<len)//保证有两个归并段
    {
        while(low1<=high1 && low2<=high2)
        {
            if(arr[low1]<=arr[low2])
            {
                brr[i++] = arr[low1++];
            }
            else
            {
                brr[i++] = arr[low2++];
            }
        }
        while(low1<=high1)
        {
            brr[i++] = arr[low1++];
        }
        while(low2<=high2)
        {
            brr[i++] = arr[low2++];
        }
        low1 = high2+1;
        high1 = low1+gap-1;
        low2 = high1+1;
        high2 =low2+gap<len-1?low2+gap-1:len-1;
    }
    //处理只有一个归并段的数据
    while(low1<len)
    {
        brr[i++] = arr[low1++];
    }

    for(int i=0;i<len;i++)
    {
        arr[i] = brr[i];
    }

    free(brr);
}
void  MergeSort(int *arr,int len)
{
    for(int i=1;i<len;i*=2)
    {
        Merge(arr,len,i);
    }
}

(4)基数排序(桶排序)针对于多关键字排序算法
算法思想:数字的话都是0—-9 准备10个桶。将数据按照一定规则先进先出(队列)
不需要关键字之间相互比较
空间复杂度:O(n) d*n
时间复杂度:O(n)
越有序越快

这里写图片描述
这里写图片描述
这里写图片描述

(5)链表排序(考试可能会考)
链表排序可以用冒泡排序实现(快速、插入、堆排序不合适)选择法排序也可以

void ListSort()
{
    int tmp;
    for(Node *p = plist->next;p->next!=NULL;p=p->next)
    {
        for(Node *q = plist->next;q->next != NULL;q=q->next)
        {
            if(q->data>q->next->data)
            {
                tmp = q->data;
                q->data = q->next->data;
                q->next->data = tmp;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值