• (学习6)特殊的分治策略算法——BFPTR


    问题引出:给出一个集合N,求出其中第k小的数,K小的元素指对集合L中的元素升序排列好后第K的元素。

    1:惯性思维是对该集合中的每个数进行排序,然后找到索引为k的元素,最好的情况应该是O(nlogn)

    2:BFPTR算法,一个即使是最坏情况下,也能达到O(n)的算法,通过对这个算法的学习,很直观的感受到,这个算法首先将集合中的数分5个一组,然后找到每组的中位数,将中位数放入一个集合,然后再求这个集合的中位数m,然后按照该中位数对数组进行划分,左边放比m小的,右边放比m大的,然后观察m的位置与k的关系进行相应递归,按照以前学过的快速排序算法,其实这个算法改变了枢纽(pivot)的选择方式,并且能明显提高算法的效率

    个人的一点理解:

    将元素分为5个一组,(这样做能使后续的划分更加合理,是由五位数学家研究出来的)对每组进行排序,则在找到中位数的中位数m后进行划分时,集合大部分已经处于有序状态,此时采取快速排序的思路,对集合进行划分,即修改快速排序的主元选取规则,将中位数集合的中位数作为主元,最坏情况下的时间复杂度也是O(n)

    伪代码(纯属个人理解,希望得到批评指正):

    1:Find(){ //找集合N中第k小的数
          FindMid();//将集合N分为5个一组,共n/5组,将每组进行插入排序,找出每组的中位数,并将其纳入集合M。
        //找出M中的中位数Mid
          FindIndex();//在集合N找到Mid的下标
          //以Mid为界,将N中比Mid小的放到Mid左边,比Mid大的放到Mid右边,并且记录划分后Mid的下标
    //若Mid的下标<k,则在Mid右边的集合找
    //若Mid的下标>k,则在Mid左边的集合找
    //若Mid的下标=k,则找到第k小的数
    }

    代码(参考了一些博主)

    //
    //  main.cpp
    //  作业6
    //
    //  Created by yizhihenpidehou on 2020/3/31.
    //  Copyright © 2020 yizhihenpidehou. All rights reserved.
    //
    #include <iostream>
    #include <stdio.h>
    using namespace std;
    const int maxen=100;
    void InsertSort(int n[],int low,int high){ //插入排序
        int i,j;
        for(i=low+1;i<=high;i++){
            j=i-1;
            int tmp=n[i];
            while(j>=low&&tmp<n[j]){
                n[j+1]=n[j];
                j--;
            }
            n[j+1]=tmp;
        }
    }
    int FindMid(int n[],int low,int high){ //找出中位数
        if(low==high) return n[low];
        int i,k;
        for(i=low;i+4<=high;i+=5){
            InsertSort(n, i, i+4);
            k=i-low;
            swap(n[low+k/5],n[i+2]);
        }
        int cnt=high-i+1;
        if(cnt>0){
            InsertSort(n, i, high);
            k=i-low;
            swap(n[low+k/5],n[i+cnt/2]);
        }
        k=k/5;
        if(k==0) return n[low];
        return FindMid(n,low,low+k);
    }
    int FindMidIndex(int n[],int low,int high,int midd){ //找出中位数的下标
        for(int i=low;i<=high;i++){
            if(n[i]==midd){
                return i;
            }
        }
        return -1;
    }
    int Partition(int n[],int low,int high,int index){ //根据求出的中位数进行划分,求出划分后中位数的位置
        if(low<=high){
            int i=low,j=high;
            swap(n[index],n[low]);
            int tmp=n[low];
            while(i!=j){
                while(i<j&&n[j]>=tmp){
                    j--;}
                n[i]=n[j];
                while(i<j&&n[i]<=tmp){
                    i++;}
                n[j]=n[i];
            }
            n[i]=tmp;
            return i;
        }
            return -1;
    }
    int BFPTR(int n[],int low,int high,int k){
        int midd=FindMid(n,low,high);
        int indexx=FindMidIndex(n,low,high,midd);
        int newIndex=Partition(n,low,high,indexx);
        int rank=newIndex-low+1;
        if(rank==k) return newIndex;
        else if(rank>k) return BFPTR(n,low,newIndex-1,k);
        return BFPTR(n,newIndex+1,high,k-rank);
    }
    int main(int argc, const char * argv[]) {
        int num[maxen]={-1,12,1,8,10,6,2,5,9,11,3,4,7};
        int k;
        scanf("%d",&k);
        int low=1;
        int high=12;
        int index=BFPTR(num,low,high,k);
        printf("%d
    ",num[index]);
        for(int i=low;i<high;i++){
            printf("%d ",num[i]);
        }
        printf("
    ");
        return 0;
    }
    View Code
  • 相关阅读:
    C++ 声明、定义、初始化、赋值
    skynet源码赏析
    python基础6函数 柒哥
    Python基础4数据类型详解下 柒哥
    Python基础1变量 柒哥
    Python基础2数据类型 柒哥
    Python基础3数据类型详解上 柒哥
    Python基础5条件分支与循环 柒哥
    PHP面试(A02)
    Envoy 配置
  • 原文地址:https://www.cnblogs.com/pipihoudewo/p/12629480.html
Copyright © 2020-2023  润新知