快速排序应用

一、一维数组快速排序

解决思路

  • 对一维数组进行多次划分,使得每次划分结束后,返回下标左边的数都小于该位置的数,右边的都大于该数。(划分函数实现)然后多次划分之后数组有序。
  • 对经过一次划分后,划分点左半部分和右半部分进行再划分,不断重复此过程直到所划分区间内只剩一个数结束,此时数组有序。(快排函数实现)
  • 用下面这组数据进行举例:
    int []ar = {56,78,12,34,90,67,100,45,23,89};

实现步骤

划分函数

  1. 先随机拿出一个数标记为 tmp(这里取0位置的数),再定义两个指针 ij ,分别从数组的两端向中间查找。
    在这里插入图片描述
  2. 从 j 位置开始判断, j 位置的数 > tmp时,j 向移动一位,直到 j 位置的数 < tmp,将 j 位置的数放到 i 位置
    在这里插入图片描述
  3. 当 i 位置的数 < tmp,i 向移动一位,直到 i 位置的数 > tmp,将 i 位置的数放到 j 位置
    在这里插入图片描述
  4. 循环进行上面 23 步的操作,直到 i 和 j 指向同一位置,将 tmp 放入该位置,一次划分结束。
    在这里插入图片描述

快排函数
pos 标记每次划分后返回的下标,对 pos 左右两边分别调用划分函数(过程与上面图示部分类似),运用递归进行多次划分,区间内只剩一个数时结束。

代码实现

//普通划分                                                         
public static int Parition(int []br,int left,int right){       
    int i = left,j = right;                                    
    int tmp = br[i];                                          
    while (i<j){                                               
        while ( i<j && br[j] > tmp){                          
            --j;                                               
        }                                                      
        if (i < j){                                            
            br[i] = br[j];                                     
        }                                                      
        while (i<j && br[i] <= tmp){                          
            ++i;                                               
        }                                                      
        if (i < j){                                            
            br[j] = br[i];                                     
        }                                                      
    }                                                          
    br[i] = tmp;                                              
    return i;                                                  
}                                                                                                  
//交换函数                                                         
private static void Swap_br(int[] br, int i, int j) {          
    int tmp = br[i];                                           
    br[i] = br[j];                                             
    br[j] = tmp;                                               
}                                                              
//单向划分                                                         
public static int Parition1(int []br,int left,int right){      
    int i = left,j = i+1;                                      
    int tmp = br[i];                                           
    while (j <= right){                                        
        if(br[j] <= tmp){                                      
            i += 1;                                            
            Swap_br(br,i,j);                                   
        }                                                      
        ++j;                                                   
    }                                                          
    Swap_br(br,left,i);                                        
    return i;                                                  
}
//随机划分                                                         
public static int RandParition(int []br,int left,int right){   
    Random random = new Random();                              
    int index = random.nextInt((right - left+1))+left;//注意点    
    int tmp = br[left];                                        
    br[left] = br[index];                                      
    br[index] = tmp;                                           
    return Parition(br,left,right);                            
}                                                                                       
//快速排序递归实现                                                     
private static void QuickPass(int[] br, int left, int right) { 
    if(left < right){                                          
        int pos = Parition(br,left,right);                     
        QuickPass(br,left,pos-1);                              
        QuickPass(br,pos+1,right);                             
    }                                                          
}                                                              
//快速排序非递归实现(应用栈 或 队列)                                          
private static void QuickPass1(int[] br, int left, int right) {
    Stack<Integer> st = new Stack<>();                         
    if(left >= right){                                         
        return;                                                
    }                                                          
    st.push(left);                                             
    st.push(right);//入栈                                        
    while(!st.isEmpty()){                                      
        left = st.pop();                                       
        right = st.pop();                                      
        int pos = Parition1(br, left, right);                  
        if(left < pos-1){                                      
            st.push(left);                                     
            st.push(pos-1);                                    
        }                                                      
        if(right > pos+1){                                     
            st.push(pos+1);                                    
            st.push(right);                                    
        }                                                      
    }                                                          
}                                                              
//打印                                                           
public static void Print_Ar(int []br){                         
    for (int i=0;i<br.length;++i){                             
        System.out.print(br[i] + " ");                         
    }                                                          
    System.out.println();                                      
}                  
//测试                                            
public static void main(String[] args) {                       
    int []ar = {56,78,12,34,90,67,100,45,23,89};               
    Print_Ar(ar);//原数组                                         
    QuickPass(ar,0,ar.length-1);                               
    Print_Ar(ar);//排序后数组                                       
}                                                              

二、单链表快速排序

解决思路

  • 单链表排序和一维数组排序类似,唯一不同的就是划分方式不同。由于单链表只有 next域,没有 prev域,因此只能从头向尾查找,进行单向划分
  • 将0位置元素的值标记为 tmp,定义两个指针 ipjp分别从前两个元素从头向尾走。
  • 如果 jp 位置的数 <= tmpip走一步,将 ipjp 位置的元素进行交换,若 jp 位置元素 > tmpjp走一步,直到 链表末尾元素判断完,0位置和 ip位置元素交换,划分结束。最终效果与上面一样,划分点左边的元素都比当前位置元素小,右边的元素都比它大。

实现步骤

划分过程如下:
在这里插入图片描述

代码实现

class LinkList{
    static class ListNode{
        int data;
        ListNode next;

        //构造函数
        public ListNode() {
            data = 0;
            next = null;
        }
        public ListNode(int x){
            data = x;
            next = null;
        }
        public ListNode(int x,ListNode narg){
            data = x;
            next = narg;
        }
    }
    ListNode head;
    public LinkList(){
        head = null;
    }
    //链表初始化
    void Init_List(int []br){
        head = new ListNode(br[0]);
        ListNode p = head;
        for(int i=1;i<br.length;++i){
            ListNode s = new ListNode(br[i]);
            p.next = s;
            p = p.next;
        }
    }
    //交换函数
    public void Swap_Node(ListNode first, ListNode second) {
        int tmp = first.data;
        first.data = second.data;
        second.data = tmp;
    }
    //划分函数
    public ListNode Parition(ListNode left,ListNode right){
        ListNode ip = left;
        ListNode jp = ip.next;
        int tmp = left.data;
        while (jp != right){
            if(jp.data <= tmp){
                ip = ip.next;
                Swap_Node(ip,jp);
            }
            jp = jp.next;
        }
        Swap_Node(left,ip);
        return ip;
    }
    //快速排序(递归实现)
    public void QuickPass(ListNode left,ListNode right){
        if(left != right){
            ListNode pos = Parition(left,right);
            QuickPass(left,pos);
            QuickPass(pos.next,right);
        }
    }
    //快速排序(非递归实现)
    public void NiceQuickSort(){
        if(head == null || head.next == null){
            return;
        }
        Queue<ListNode> q = new LinkedList<>();
        q.offer(head);
        q.offer(null);
        while (!q.isEmpty()){
            ListNode left = q.poll();
            ListNode right = q.poll();
            ListNode p = Parition(left,right);
            if(left != p){
                q.offer(left);
                q.offer(p);
            }
            if(p.next != right){
                q.offer(p.next);
                q.offer(right);
            }
        }
    }
    //打印
    public void Print_List(){
        ListNode p = head;
        while (p != null){
            System.out.print(p.data + " ");
            p = p.next;
        }
        System.out.println();
    }
}
public class TestDemo4_18_2 {
    public static void main(String[] args) {
        int []ar = {56,78,12,34,90,67,100,45,23,89};
        LinkList myt = new LinkList();
        myt.Init_List(ar);
        myt.Print_List();
        myt.QuickPass(myt.head, null);
        myt.Print_List();
    }
}

三、应用快速排序找数组前两大的数

解决思路

  • 先将前两个数进行比较,大的赋值给max1,小的赋值给max2。然后将其他数据与这两个值进行比较,不断更新max1和max2。
  • 从第三个数开始向后遍历,比max1大,当前位置的值变为max1,第一大变为第二大(原max1变为max2);比max2大,当前位置的值变为max2。

实现

//找出前两大数                                                  
private static void Print_2Max(int[] ar) {                
    int max1 = (ar[0]>ar[1]) ? ar[0] : ar[1];             
    int max2 = (ar[0]>ar[1]) ? ar[1] : ar[0];             
    for(int i = 2;i<ar.length;++i){                       
        if(ar[i] > max1){                                 
            max2 = max1;                                  
            max1 = ar[i];                                 
        }else if(ar[i] >max2){                            
            max2 = ar[i];                                 
        }                                                 
    }                                                     
    System.out.printf("max1 : %d max2 : %d \n",max1,max2);
}                                                         
public static void main(String[] args) {        
    int []ar = {56,78,12,34,90,67,100,45,23,89};
    Print_2Max(ar);                                                 
}                                               

四、应用快速排序查找数组中第k小的数

解决思路

  • 先对数组进行划分和一次快速排序,再在数组中进行查找。
  • 一次排序后,返回下标元素左边的元素都比它小,右边的数都比它大,将该下标标记为 index。由于数组下标从0开始,所以 index左边(包括自身)应该有 index-left+1(left为当前划分区间最左边元素的下标)个元素,将 index-left+1 标记为 pos
  • k 比pos小或者等于 pos,则要找的元素在pos左边,递归pos左半部分比 pos大递归右半部分

实现

//快速排序查找
private static int Print_K(int[] ar, int left, int right,int k) {  
    if(left == right && k == 1){                                   
        return ar[left];                                           
    }                                                              
    int index = Parition(ar,left,right);                           
    int pos = index - left + 1;                                    
    if(k <= pos){                                                  
        return Print_K(ar,left,index,k);                           
    }else {                                                        
        return Print_K(ar,index+1,right,k-pos);                    
    }                                                              
}                                                                  
//交换函数                                                             
private static void Swap_br(int[] br, int i, int j) {              
    int tmp = br[i];                                               
    br[i] = br[j];                                                 
    br[j] = tmp;                                                   
}         
//划分函数                                                         
public static int Parition(int []br,int left,int right){           
    int i = left,j = i+1;                                          
    int tmp = br[i];                                               
    while (j <= right){                                            
        if(br[j] <= tmp){                                          
            i += 1;                                                
            Swap_br(br,i,j);                                       
        }                                                          
        ++j;                                                       
    }                                                              
    Swap_br(br,left,i);                                            
    return i;                                                      
}          
//打印                                                       
public static void Print_K_Min(int k,int []ar){                    
    System.out.printf("%d => %d \n",k,Print_K(ar,0,ar.length-1,k));
}             
//测试                                                     
public static void main(String[] args) {        
    int []ar = {56,78,12,34,90,67,100,45,23,89};
    Print_2Max(ar);                             
    Print_K_Min(3,ar);                          
}    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值