双指针(归并排序,快速排序)

1.归并排序

关键概念:双列表指针,临时数组

  1. 双列表指针:分别遍历两个有序数组

  2. 临时数组:暂时保存合并之后的结果

public int[] merge(int[] list1, int[] list2){
    int l1 = list1.length;
    int l2 = list2.length;
    int[] newlist = new int[l1 + l2];
    int n = 0;
    int m = 0;
    int i
    while(n < l1 && m < l2){
        if(list1[n] > list2[m]){
            newlist[index++] = list2[m];
        }else{
            newlist[index++] = list1[n];
        }
    }
    
    while(n < l1) newlist[index++] = list1[n];
    while(m < l2) newlist[index++] = list2[m];
    return newlist;
}

递归版归并排序:自顶向底

public void mergeSort(int[] list, int left, int right){
    if(left < right){
        int mid = left + (right - left)/2;
        mergeSort(list, left, mid);
        mergeSort(lsit, mid+1, righr);
        merge(list, left, mid, mid + 1, right);
    }
}

非递归版归并排序:自底向顶

public void mergeSort2(int[] list, int left, int right){
    int n = right - left + 1;
    for(int step = 2; step / 2 <= n; step *= 2){//保证结束时,
        for(int i = left; i <= right; i += step){
            //将区域分为[left, mid] 和[mid +1, right] ,左侧有step/2个元素 
            int mid = i + step / 2 - 1;
            if(mid + 1 <= right){//保证右半个区[mid +1, right]域有数据 
                merge(list, i, mid, mid + 1, min(i + step - 1,right));
            }
        }
    }
}

2.快速排序

  1. 把序列按照第一位分成两部分:
public static int partition(int[] list, int left, int right){
    int p = (int)(left + Math.random()*(right - left))
    swap(list, p, left);
    int temp = list[left];
    while(left < right){
        //小于等于temp的数全部移动到temp的左边
        while(left < right && list[right] > temp) right--;
        list[left] = list[right];
        //大于temp的数全部移动到temp的右边
        while(left < right && list[left] <= temp) left++;
        list[right] = list[left];
    }
    list[left] = temp;
    return left;
}
  1. 使用递归排序:
public static void quickSort(int[] list, int left, int right){
    if(left < right){
        int pos = partition(list, left, right);
        quickSort(list, left, pos - 1);
        quickSort(list, pos + 1, right);
    }
}

3.随机选择算法

核心:寻找第一个数,把列表分为两部分。

//将数据分成两部分的算法,此部分为核心代码
int partition(int[] list, int left, int right){
    int p = (int)(left + Math.random() * (right - left));
    swap(list, left, p);
    int temp = list[left];
    while(left < right){
        while(left < right && list[right] >= temp)) right--;
        list[left] = list[right];
        while(left < right && list[left] < temp) left++;
        list[right] = list[left];  
    }
    list[left] = temp;
    return left;
}

//选择第k大的数,递归写法
int randSelect(int[] list, int left, int right, int k){
    if(left == right) return left;
    int p = partition(list, left, right);
    int M = p - left + 1;//表示p为从left开始的第M大的数
    if(M == k){
        return p;
    }else if(M > k){
        return randSelect(list, left, p - 1, k);
    }else{
        return randSelect(list, p + 1, right, k - M);
    }
}

//选择第k大的数,循环写法
int randSelect(int[] list, int k){
    int left = 0;
    int right = list.length - 1;
    while(left < right){
        int pos = partition(list, left, right);
        if(pos + 1 == k){
            return pos;
        }else if(pos + 1 > k){
            right = pos - 1;
        }else{
            left = pos + 1;
        }
    }
    return left;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值