荷兰国旗问题
-
问题描述
荷兰国旗问题 给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边, 等于num的数放在数组的中间, 大于num的数放在数组的 右边。 要求额外空间复杂度O(1),时间复杂度O(N)
-
此处引出快速排序思想,解法,假设两个指针分别指向arr数组的第一个元素和最后一个元素,将第一个元素与num相比较,如果第一个元素小于num,则该元素与第一个指针所指元素交换(即第一个元素与第一个元素交换,不变),接着指针一向前移动,num与第二个元素比较如果等于不变,如果大于则与第二个指针所指元素交换,但此时的num所比较的在数组中的位置不发生改变,如果小于num则与第一个指针所指元素交换,依次类推,知道num比较的位置与第二个指针所指位置相同结束比较
/**
* 荷兰国旗问题
*
* 给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边,
* 等于num的数放在数组的中间,
* 大于num的数放在数组的 右边。
* 要求额外空间复杂度O(1),时间复杂度O(N)
*
*/
public static int[] partition(int[] arr, int L, int R, int num) {
//假设的第一个指针位置
int less = L-1;
//假设的第二个指针位置
int more = R+1;
//元素num所比较的位置
int index = L;
while(index<more) {
if(arr[index]<num) {
//less++;
//元素num>数组元素时的情况
swap(arr,++less,index++);
}else if(arr[index]>num) {
//more--;
//当大于num时,由于右半边界的数未知,所以保持数组不变
swap(arr,--more,index);
}else {
//相等的情况
index++;
}
}
//返回交换后的边界
return new int[] {less+1,more-1};
}
//交换函数
public static void swap(int[] arr,int L,int R) {
int t = arr[L];
arr[L] = arr[R];
arr[R] = t;
}
快速排序
- 理解:此处用的快速排序的方法是用数组的最后一个元素作为划分,将小于该元素的划分到左边,大于该元素的划分到右边等于该元素的划分到中间,具体过程和上述的荷兰国旗问题的思路相同,用递归进行整体的排列.
- 时间复杂度:最坏情况,所划分的元素为最大或者最小,只有最左边和最右边有元素,此时时间复杂度为O(N^2). 最好的情况:选定元素的大小是数组的中间元素左右元素个数相同,此时时间复杂度为O(nlogn)
//快速排序
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
int[] p = partition(arr, l, r);
//再次取出最后的元素,返回值得下标-1是取出与之前元素不同的下标
quickSort(arr, l, p[0] - 1);
//与上述同理
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
//此处拿出最后一个元素进行比较,暂时不对他进行交换
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
//将未交换的最后一个元素交换
swap(arr, more, r);
//返回交换后数组中间与最后一个元素相同的那部分元素的区间下标
return new int[] { less + 1, more };
}
//交换函数
public static void swap(int[] arr, int L, int R) {
int t = arr[L];
arr[L] = arr[R];
arr[R] = t;
}
随机快速排序
- 为了减少快速排序的时间复杂度,改进的快速排序的算法,就是采用随机取数,随机从数组中拿取元素,拿到每个元素的概率是相同的,此处算出的算法的时间复杂度的数学期望是O(nlogn)
- 代码基本与上述相同,就是将上述的取最后一个元素进行比较的情况改变为取随机数,取出一个随机数,与数组中的最后一个元素交换
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
swap(arr, more, r);
return new int[] { less + 1, more };
}
//交换函数
public static void swap(int[] arr, int L, int R) {
int t = arr[L];
arr[L] = arr[R];
arr[R] = t;
}