求解顺序统计量的7种方法

二.排序算法求解顺序统计量

        该内容属于比较基础的内容,随便选择一种排序算法就可以实现对数组的排序,从而在有序数组中找到第k大的元素。这里给出一种IntroSort的方法,即是一种使用堆排序和快速排序的HybirdSort算法,维基百科定义如下:

        下面分别给出头文件IntroSort.h和源文件IntroSort.c以及测试文件main.c,运行main.c即可。

        C语言代码如下:

        IntroSort.h

//
// Created by Long on 2021/12/1.
//

#ifndef INTROSORT_INTROSORT_H
#define INTROSORT_INTROSORT_H

/*
 * A hybird algorithm base on quick sort 、heap sort and insert sort.
 */

#define LIMIT1 50 //Heap Sort 的阈值
#define LIMIT2 10 //Insert Sort 的阈值

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//对外的接口
void IntroSort(int *array, int size);

//主要的内容
void Intro(int *array, int left, int right);

//处理pivot的左右两侧数据 conqueror 标准版
int Parting(int *array, int left, int right);

//随机版 且利用三数取中
int RandomParting(int *array, int left, int right);


//插入排序
void InsertSort(int *array, int left, int right);

//堆排序
void ShowArray(const int *array,int size);

void HeapSort(int *Data,int size);

void PercolateDown(int*heap,int index,int size);

void BuildHeap(int *heap,int size);

void Swap(int *num1,int *num2);
#endif //INTROSORT_INTROSORT_H

        IntroSort.c

//
// Created by 周龙 on 2021/12/1.
//


#include "IntroSort.h"



//对外的接口
void IntroSort(int *array, int size) {
    Intro(array, 0, size - 1);
}

void Intro(int *array, int left, int right) {
    if (right - left + 1 > LIMIT2) {
        //添加阈值
        while (left < right) {
            int p = RandomParting(array, left, right);
            //p为主元的位置 主元的位置无需改变
            Intro(array, left, p - 1);
            left = p + 1;//向右递归
        }
    } else if(right-left+1 > LIMIT1) {
        int buf [right-left+1];
        for(int i=0;i<=right;i++){
            buf[i] = array[i+left];
        }
        HeapSort(buf,right-left+1);//堆排序
        for(int i=0;i<=right;i++){
            array[i+left] = buf[i];
        }
    }
    else{
        InsertSort(array,left,right);//插入排序
    }
}

//为该区间以right作为主元进行划分
int Parting(int *array, int left, int right) {
    //取最右侧数据为pivot
    int pivot = array[right];
    //划分pivot左右两边的数据
    int i = left - 1, j = left;//令i为left-1开始 可以避免极端情况
    for (; j < right; j++) {
        //如果小于左元则和i交换 令i+1处永远都是大于主元的数据
        if (array[j] < pivot) {
            i++;
            Swap(&array[j], &array[i]);
        }
    }
    Swap(&array[i + 1], &array[right]);//不能直接拿pivot交换 而要改变right的数据
    return i + 1;//i+1则是pivot所在的位置
}


//利用随机函数划分主元
int RandomParting(int *array, int left, int right) {
    //生成left到right之间左开右闭区间的随机数
    //如果和边界相等又该如何
    //不存在right == left 的情况
    int site = rand() % (right - left) + left + 1;//如果遇到right和left相等的情况 这样取值就会error
    if (site > right || site < left) {
        fprintf(stderr, "This random number is wrong\n");
    }
    //保证最右侧数据为pivot
    if (array[left] > array[right]) {
        Swap(&array[left], &array[right]);
    }
    if (array[left] > array[site]) {
        Swap(&array[left], &array[site]);
    }
    if (array[site] > array[right]) {
        Swap(&array[site], &array[right]);
    }
    Swap(&array[site], &array[right]);//交换right和site的位置
    int pivot = array[right];
    //划分pivot左右两边的数据
    int i = left - 1, j = left;//令i为left-1开始 可以避免极端情况
    for (; j < right; j++) {
        //如果小于左元则和i交换 令i+1处永远都是大于主元的数据
        if (array[j] < pivot) {
            i++;
            Swap(&array[j], &array[i]);
        }
    }
    Swap(&array[i + 1], &array[right]);//不能直接拿pivot交换 而要改变right的数据
    return i + 1;//i+1则是pivot所在的位置
}





void InsertSort(int *array, int left, int right) {
    int temp;
    for (int i = left + 1; i <= right; i++) {
        temp = array[i];
        int j = i - 1;
        for (; j >= left; j--) {
            if (array[j] > temp) {
                array[j + 1] = array[j];
            } else {
                break;
            }
        }
        array[j + 1] = temp;//空穴位置
    }
}

void HeapSort(int *Data,int size){
    //以数组元素建堆
    BuildHeap(Data,size);
    //每次取出堆顶元素 取size-1次 交换最后一个元素的位置
    int temp=size;
    for(int i=0;i<temp-1;i++){
        Swap(&Data[0],&Data[size-1]);
        size-=1;
        PercolateDown(Data,1,size);
    }
}

void Swap(int *num1,int *num2){
    int temp=*num1;
    *num1=*num2;
    *num2=temp;
}

//Percolate down the every root node
void BuildHeap(int *heap,int size){
    //开始调整节点 从含有child的首个root开始
    for(int i=(size+1)/2;i>=1;i--){
        PercolateDown(heap,i,size);//以该处的元素下滤 类似于插入排序
    }
}

//需要加入边界判断值 删除前是否为空 为空则无法删除  percolate down
void PercolateDown(int*heap,int index,int size){
    //size是边界值 直接使用size传入实则是在原可访问区域+1 则无需+1处理
    int child;
    int i;
    int data=heap[index-1];
    for(i=index;i*2<=size;i=child){
        child=i*2;//i的child
        if(child+1<=size&&heap[child-1]<heap[child]){
            child++;//右侧节点存在且大于左侧 则更新child为待移动节点
        }
        if(heap[child-1]>data){
            heap[i-1]=heap[child-1];//赋值为自己的最大child
        }
        else{
            break;
        }
    }
    //确保for外部就是待插入的位置
    heap[i-1]=data;
}

void ShowArray(const int *array,int size){
    for(int i=0;i<size;i++){
        printf("%d ",array[i]);
        if ((i + 1) % 10 == 0) {
            putchar('\n');
        }
    }
    putchar('\n');
}

        main.c

#include "IntroSort.h"

int main(int argc, char *argv[]) {
    srand((unsigned int) time(NULL));
    int array[10];
    for (int i = 0; i < 10; i++) {
        array[i] = rand() % 11;
    }
    int size = sizeof array / sizeof array[0];
    ShowArray(array, size);
    IntroSort(array, size);
    ShowArray(array, size);
    int k = 4;
    printf("第%d大的元素为:%d\n",k,array[k-1]);
    return 0;
}

运行结果如下:

欢迎大家指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值