各个排序算法应用:求取数组中第K大的数( LeetCode 215. Kth Largest Element in an Array )

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5

Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

Note: 

You may assume k is always valid, 1 ≤ k ≤ array's length.

以下为各个算法相应的代码

int findKthLargest(int* nums, int numsSize, int k) {
    int i,j;
    int t;
    int max;
    
       /*
1、冒泡法********************************************************************************************
    //通过从左到右不断交换相邻逆序的相邻元素,在一轮的交换之后,可以让未排序的元素上浮到最右侧,是的右侧是已排序的。在一轮交换中,如果没有发生交换,就说明数组已经是有序的,此时可以直接退出。


    for(i=0;i<numsSize-1;i++)
        for(j=1;j<numsSize-i;j++)
        {
            if(nums[j]>nums[j-1]){
                int t=nums[j];
                nums[j]=nums[j-1];
                nums[j-1]=t;
            }
        }
    return nums[k-1];
    
    */  
    
    
    
       /*
2、插入排序******************************************************************************************
    //插入排序从左到右进行,每次都将当前元素插入到左侧已经排序的数组中,使得插入之后左部数组依然有序。第 j 元素是通过不断向左比较并交换来实现插入过程:当第 j 元素小于第 j - 1 元素,就将它们的位置交换,然后令 j 指针向左移动一个位置,不断进行以上操作。

    for(i=0;i<numsSize-1;i++){


        for(j=i+1;j>0;j--){
            if(nums[j]>nums[j-1]){
                t=nums[j];
                nums[j]=nums[j-1];
                nums[j-1]=t;
            }
            else{
                break;
            }  
        }
    }
    return nums[k-1];
    */ 
    
    
         /*
3、选择排序,每次选择最大的排在第k个位置****************************************************************
    //选择出数组中的最小元素,将它与数组的第一个元素交换位置。再从剩下的元素中选择出最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。
    for(i=0;i<k;i++)  
    {
        t=i;
        max=nums[i];
        for(j=i+1;j<numsSize;j++){
            
            if(nums[j]>max){
                t=j;
                max=nums[j];
            }
        }
        int a=nums[i];
        nums[i]=max;
        nums[t]=a;    
    }
    return nums[k-1];
    */
    
        /*
4、归并排序*****************************************************************************************

    if(numsSize==1)
        return nums[0];
    
    sort_2(nums,0,numsSize-1);
    
    return nums[k-1];
    */
    
    
    /*
5、希尔排序*****************************************************************************************
//对于大规模的数组,插入排序很慢,因为它只能交换相邻的元素,每次只能将逆序数量减少 1。
    //希尔排序的出现就是为了改进插入排序的这种局限性,它通过交换不相邻的元素,每次可以将逆序数量减少大于 1。
    //希尔排序使用插入排序对间隔 h 的序列进行排序。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。
    int gap;  //跳跃的步数
    for(gap=numsSize/2;gap>=1;gap=gap/2){
        
        for(i=0;i<numsSize-gap;i++){
            
          
            for(j=i+gap;j-gap>=0;j=j-gap){   //对gap内的数组进行插入排序
                
                if(nums[j]>nums[j-gap]){
                    
                    int aaa=nums[j];
                    nums[j]=nums[j-gap];
                    nums[j-gap]=aaa;
                }
                
                
            }
            
        } 
    }
    return nums[k-1];
    */
    
    
    
    
    
    /*
6、快速排序**************************************************************************************
    sort(nums,0,numsSize-1);
    return nums[k-1];
    */
    
    
    
    /*
7、基于切分的快速选择排序************************************************************************
     //时间复杂度O(n)
    //该算法是线性级别的,因为每次正好将数组二分,那么比较的总次数为 (N+N/2+N/4+..),直到找到第 k 个元素,这个和显然小于 2N。
    int low=0;
    int high=numsSize-1;
    
    while(high>low){
        
        int q;
        q=splite_num(nums,low,high); //获得切分的下标,并排好序
        if(q==k-1){
            break;
        }
        if(q>k-1){
            high=q-1;
        }
        else{
            low=q+1;
        }
        
    }
    return nums[k-1];
    */
    
    
    
    /*
8、堆排序********************************************************************************************
    // 参考 https://www.cnblogs.com/chengxiao/p/6129630.html
    //1.构建大顶堆
    for(int i=numsSize/2-1;i>=0;i--){
            //从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(nums,i,numsSize);
    }
    //2.调整堆结构+交换堆顶元素与末尾元素
    for(int j=numsSize-1;j>0;j--){
        
            swap(nums,0,j);//将堆顶元素与末尾元素进行交换
            
            adjustHeap(nums,0,j);//重新对堆进行调整
    }
    return nums[numsSize-k];
    */ 
    
    //********************************************************************************************
    
    
}




#################################################################################################

void adjustHeap(int *arr,int i,int length){   //1.构建大顶堆 
        int temp = arr[i];//先取出当前元素i
        for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
            if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
                k++;
            }
            if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
                arr[i] = arr[k];
                i = k;
            }else{
                break;
            }
        }
        arr[i] = temp;//将temp值放到最终的位置
}
    /**
     * 交换元素
     * @param arr
     * @param a
     * @param b
     */
void swap(int *arr,int a ,int b){  //交换元素
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
}




###############################################################################################

void  sort(int *nums,int low,int high){     //快速排序
    
    //•归并排序将数组分为两个子数组分别排序,并将有序的子数组归并使得整个数组排序;
//•快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。


    
    if(high<=low)
        return;
    int q;
    q=splite_num(nums,low,high); //获得切分的下标,并排好序
    sort(nums,low,q);
    sort(nums,q+1,high);
}

int splite_num(int *nums,int low,int high){          //获得切分的下标,并排好序
    //取 a[low] 作为切分元素,然后从数组的左端向右扫描直到找到第一个大于等于它的元素,再从数组的右端向左扫描找到第一个小于等于它的元素,交换这两个元素,并不断进行这个过程,就可以保证左指针 i 的左侧元素都不大于切分元素,右指针 j 的右侧元素都不小于切分元素。当两个指针相遇时,将切分元素 a[low] 和 a[j] 交换位置。
    
    int a=nums[low];
    int i=low+1;
    int j=high;
    while(1){
        
        while(i<high && nums[i]>=a)   //搜索nums[i]<a,当 nums[i]==a的时候,可以分配到另一个数组里,保证公平分配
        {
            i++;
        }
        
        while(j>low && nums[j]<=a)   //搜索nums[j]>a,当 nums[i]==a的时候,可以分配到另一个数组里,保证公平分配
        {
            j--;
        }
        if(i>=j){
            break;
        }
        else{
            
            int ttt=nums[i];
            nums[i]=nums[j];
            nums[j]=ttt;
            i++;
            j--;
            
        }
       
        
    }
    int ttt=nums[low];
    nums[low]=nums[j];
    nums[j]=ttt;
    return j;
    
}


##############################################################################################
int sort_2(int *nums,int low,int high){  //归并排序
    // //归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。自顶向下归并排序
    if(high<=low)
        return;
    int middle=low+(high-low)/2;
    sort_2(nums,low,middle);
    sort_2(nums,middle+1,high);
    merge(nums,low,middle,high);                     //合并两个降序的数组
}

void merge(int *nums,int low,int middle,int high){   //合并两个降序的数组
    
    int i,j;
    i=low;
    j=middle+1;
    int k=0;
    int b[high-low+1];
    
    while((i<=middle)&&(j<=high)&&(k<high-low+1)){
        
        if(nums[i]<nums[j]){
            
            b[k]=nums[j];
            j++;
            
        }
        else{
            b[k]=nums[i];
            i++;
        }
        k++;
        
    }
    
    if(i>middle && j<=high){
        for(;j<=high;j++){
            b[k]=nums[j];
            k++;
        }
        
    }
    if(j>high && i<=middle){
        for(;i<=middle;i++){
            b[k]=nums[i];
            k++;
        }
        
    }
    for(i=low;i<=high;i++)
        nums[i]=b[i-low]; 
}

#############################################################################################


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值