1.快速排序
定义:它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
代码实现:
public static int Partion(int[] arr,int left ,int right){
int temp=arr[left];
while(left<right) {
while (left<right&&arr[right]>temp) --right;
if (left < right) {
arr[left] = arr[right];
}
while (left<right&&arr[left] <= temp) ++left;
if (left < right) {
arr[right] = arr[left];
}
}
arr[left]=temp;
return left;
}
public static void quickSort(int[] arr,int left,int right){
if(left<right){
int pos=Partion1(arr,left,right);
quickSort(arr,left,pos-1);
quickSort(arr,pos+1,right);
}
}
public static void main(String[] args) {
int[] arr={12,34,9,6,32,89,76,56};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
由代码可以发现,快排即使用的是递归方法进行排序,使用非递归的代码如下:
非递归:
//非递归
public static void NiceQuickSort(int[] arr,int left,int right){
Queue<Integer> queue=new LinkedList<>();
queue.offer(left);
queue.offer(right);
while (!queue.isEmpty()){
left=queue.poll();
right=queue.poll();
int pos=Partion(arr,left,right);
if(left<pos-1){
queue.offer(left);
queue.offer(pos-1);
}
if(pos+1<right){
queue.offer(pos+1);
queue.offer(right);
}
}
}
**问题思考:**有时候会出现所要排序的数组其本身有序,此时用快排反而更耗时,采用随机排序,即不从0位开始找,从任意位置开始查找,这样既可提高时间复杂度。
public static int RandomPartion(int[] arr,int left,int right) {
Random random=new Random();
int index=random.nextInt(right-left+1)+left;
int temp=arr[left];
arr[left]=arr[index];
arr[index]=temp;
return Partion(arr,left,right);
}
**问题思考:**如果需要进行快排的不是数组而是单链表,如何进行排序?
单链表:即只有一个指针next,不能从后往前,所以需要从前到后单方向进行排序。可类比思考数组如何单方向进行快排?
数组单方向快排:
解释:
同时添加i和j,从i=left开始,j=i+1,即j比较是否有temp(arr[left])值大,如果没有则将i++,同时交换i下标和j下标所对应的数值。(此时i下标对应的值一定不会小于temp,符合逻辑 ),如果比temp值大,则j++直到j到right的位置。最后交换temp和arr[i]的值即可。
//单方向排序
public static int Partion1(int[] arr,int left ,int right) {
int temp = arr[left];
int i = left, j = i + 1;
while(j<=right) {
if(arr[j]<temp){
i++;
int x=arr[i];
arr[i]=arr[j];
arr[j]=x;
}
++j;
}
arr[left]=arr[i];
arr[i]=temp;
return i;
}
链表快排 (即单方向排序):
public static ListNode ListPartion(ListNode left,ListNode right){
int tmp=left.value;
ListNode low=left,hight=low.next;
while(hight!=right){
if(hight.value<=tmp){
low=low.next;
if(low!=hight) swap(low,hight);
}
hight=hight.next;
}
swap(left,low);
return low;
}
public static void ListQuickSort(ListNode left,ListNode right){
if(left!=right){
ListNode pos=ListPartion(left, right);
ListQuickSort(left,pos);
ListQuickSort(pos.Next,right);
}
}
**问题思考:**找出数组中的第一小和第二小元素
分析:将数组中的前两个值作为最小的两个值 min1,min2,从第三个元素开始进行比较,如果arr[i]小于min1,则min2=min1,min1=arr[i],;如果arr[i]小于min2,则min2=arr[i]
//找出数组中的第一小和第二小元素
public static void Select2Min(int[] arr ){
if(arr.length<2)return;
int min1=arr[0]<arr[1]?arr[0]:arr[1];
int min2=arr[0]>arr[1]?arr[0]:arr[1];
for (int i = 2; i < arr.length; i++) {
if(arr[i]<min1){
min2=min1;
min1=arr[i];
}
else if(arr[i]<min2){
min2=arr[i];
}
}
System.out.println(min1+" "+min2);
}
**问题思考:**找出数组中的第k小元素
分析:由于快排我们可以知道当第一次划分时,arr[left]应该对应的下标我们即可知道,同时根据他的下标值:pos-left+1即可知道他排行第几(即为第几小),此时判断要查找的第k位与该排名的大小关系,如果大于该排名,则调用该函数将要查找的k位改为k-pos位Select_K(arr,index+1,right,k-pos),如果小于等于当前位次,则调用该函数Select_K(arr,left,index,k)
public static int Select_K(int[] arr,int left,int right,int k){
if(left==right&&k==1)return arr[left];
int index=Partion(arr,left,right);
int pos=index-left+1;//表示经过查找一次后对应的位数 即第几小
if(k<=pos) return Select_K(arr,left,index,k);
else return Select_K(arr,index+1,right,k-pos);
}
问题思考:如何找数组中差距最小的两个数的差值。
分析:开始将一个数组划分成两部分,利用Select_K(arr,left,right,k)将数组可划分成两段,分别查找出左边和右边部分对应的两个数差的最小值,还有一个差值即:第二部分的最小值减去第一部分的最大值,比较找出差值最小的值。
public static int MaxS1(int[] arr,int left,int right){
return arr[right];
}
public static int Mins2(int[] arr,int left,int right){
int temp=arr[left];
for (int i = left+1; i <=right; i++) {
if(temp>arr[i]) temp=arr[i];
}
return temp;
}
public static int Min3d(int a,int b,int c){
int min=a<b?a:b;
return min<c?min:c;
}
static final int maxint=0x7ffff;
public static int Cpair(int[] arr,int left,int right){
if(right-left<1)return maxint;
int k=(right-left+1)/2;
Select_K(arr,left,right,k);
int index=left+k-1;
int d1=Cpair(arr,left,index);
int d2=Cpair(arr,index+1,right);
int maxs1=MaxS1(arr,left,index);
int mins2=Mins2(arr,index+1,right);
return Min3d(d1,d2,mins2-maxs1);
}