版权声明:版权没有,转载随意 https://blog.csdn.net/MAOZEXIJR/article/details/81986785
一、冒泡排序优化、再优化
1、简单冒泡排序
/**
* 冒泡排序
*/
public static void bubbleSort() {
int[] array = {6, 5, 4, 3, 2, 1};
int end = array.length - 1;
for (int i = 0; i < end; i++) {
for (int j = 0; j < end - i; j++) {
if (array[j] >= array[j + 1]) {//逐位比较
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
//↑实现一次位置交换
}
}
//↑冒出一个最大数
}
}
示例图:
2、冒泡排序优化
/**
* 冒泡排序优化
*/
public static void bubbleSort() {
int[] array = {-2, -1, 0, 6, 5, 4, 3, 2, 1};
int end = array.length - 1;
for (int i = 0; i < end; i++) {
boolean ordered = true;//前段数字已排序
for (int j = 0; j < end - i; j++) {
if (array[j] >= array[j + 1]) {//逐位比较
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
//↑实现一次位置交换
ordered = false;//发生位置交换,即前段数字未排序
}
}
//↑冒出一个最大数
if (ordered) {//前段数字已排序
break;
}
}
}
3、冒泡排序再优化
/**
* 冒泡排序再优化
*/
public static void bubbleSort() {
int[] array = {6, 5, 4, 3, 2, 1, 7, 8, 9};
int end = array.length - 1;
for (int i = 0; i < array.length - 1; i++) {
boolean ordered = true;//前段数字已排序
int index = 0;//后段数字已排序的下标
for (int j = 0; j < end; j++) {
if (array[j] >= array[j + 1]) {//逐位比较
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
//↑实现一次位置交换
ordered = false;//发生位置交换,即前段数字未排序
index = j + 1;
}
}
//↑冒出一个最大数
if (ordered) {//前段数字已排序
break;
}
end = index;
}
}
二、快速排序7种实现方式
1、挖坑填坑法
(1)思维模型:
(2)执行流程:
1)取数组第一个数作为基准数 pivot
2)数组从右向左遍历查找 ≤pivot 的值,将找到的数与基准数对调位置
3)数组从左往右遍历查找 >pivot 的值,将找到的数与基准数对调位置
4)循环2、3步骤,当所有数字都遍历一遍后,数组被划分为3个区间:小于等于区、基准数、大于区
5)分别对小于等于区、大于区执行如上流程,直至全部排序完成
(3)代码实现:
/**
* 快速排序 — 挖坑填坑法
* 速度排名:2/6
*
* @param array
* @param begin
* @param end
*/
public static void digAndFill(int array[], int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
int left = begin;
int right = end;
int pivot = array[begin];//基准数
while (left < right) {
while (left < right && pivot < array[right]) {
//从右往左遍历,在 "未知区" 筛选出一组 "大于区" 的数
right--;
}
if (left < right) {
//在 "未知区" 筛选出一个 "小于等于区" 的数
int temp = array[right];
array[right] = array[left];
array[left] = temp;
left++;
}
while (left < right && array[left] <= pivot) {
//从左往右遍历,在 "未知区" 筛选出一组 "小于等于区" 的数
left++;
}
if (left < right) {
//在 "未知区" 筛选出一个 "大于区" 的数
int temp = array[right];
array[right] = array[left];
array[left] = temp;
right--;
}
}
if (begin < left) {
digAndFill(array, begin, left - 1);//排序 "小于等于区"
}
if (right < end) {
digAndFill(array, left + 1, end);//排序 "大于区"
}
}
2、一端挖坑一端填
(1)思维模型:
(2)执行流程:
1)取数组第一个数作为基准数 pivot,数组首位作坑("左坑")
2)数组从右向左遍历查找 ≤pivot 的值,将找到的数值填入前一步的 "左坑",并在当前位置作新坑("右坑")
3)数组从左往右遍历查找 >pivot 的值,将找到的数值填入前一步的 "右坑",并在当前位置作新坑("左坑")
4)循环2、3步骤,当所有数字都遍历一遍后,数组被划分为3个区间:小于等于区、坑、大于区
5)将基准数填入最后的坑里
6)分别对小于等于区、大于区执行如上流程,直至全部排序完成
(3)代码实现:
/**
* 快速排序 — 一端挖坑一端填
* 速度排名:6/6
*
* @param array
* @param begin
* @param end
*/
public static void sideDigSideFill(int[] array, int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
int left = begin;//坑所在下标 或 "未知区" 首位下标
int right = end;//"未知区" 末位下标 或 坑所在下标
int pivot = array[begin];//基准数,开始挖 "左坑"
while (left < right) {
while (left < right && pivot < array[right]) {
//从右往左遍历,在 "未知区" 筛选出一组 "大于区" 的数
right--;
}
//此时 array[right] ≤pivot
array[left] = array[right];//用 "右值" 填 "左坑",并挖 "右坑"
left++;
while (left < right && array[left] <= pivot) {
//从左往右遍历,在 "未知区" 筛选出一组 "小于等于区" 的数
left++;
}
//此时 array[left]>pivot
array[right] = array[left];//用 "左值" 填 "右坑",并挖新 "左坑"
right--;
}
//此时 left = right = 坑所在下标
array[left] = pivot;//用 基准数 填 "左坑",结束挖坑
if (begin < left) {
sideDigSideFill(array, begin, left - 1);//排序 "小于等于区"
}
if (right < end) {
sideDigSideFill(array, left + 1, end);//排序 "大于区"
}
}
3、两端收缩法
/**
* 快速排序 — 两端收缩法
* 速度排名:3/6
*
* @param array
* @param begin
* @param end
*/
public static void twoSideShrink(int[] array, int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
int left = begin + 1;
int right = end;
int pivot = array[begin];//中枢,参考值
while (left < right) {
while (left < right && array[left] <= pivot) {
left++;
}
while (left < right && pivot <= array[right]) {
right--;
}
if (left < right) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
left++;
right--;
}
}
if (pivot <= array[right]) {
right--;
}
array[begin] = array[right];//中枢调换位置
array[right] = pivot;
if (begin < right - 1) {
twoSideShrink(array, begin, right - 1);//左半切片
}
if (right + 1 < end) {
twoSideShrink(array, right + 1, end);//右半切片
}
}
4、单端二切法
/**
* 快速排序 — 单端二切法
* 速度排名:5/6
*
* @param array
* @param begin
* @param end
*/
public static void oneSide2Cut(int[] array, int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
int left = begin;// "小于等于区" 末位下标
int right = begin + 1;// "未知区" 首位下标
int pivot = array[begin];//中枢,参考值
while (right <= end) {
if (pivot >= array[right]) {
int temp = array[left + 1];
array[left + 1] = array[right];
array[right] = temp;
left++;
right++;
} else {
right++;
}
}
int temp = array[begin];
array[begin] = array[left];
array[left] = temp;
if (begin < left - 1) {
oneSide2Cut(array, begin, left - 1);
}
if (left + 1 < end) {
oneSide2Cut(array, left + 1, end);
}
}
5、三切4分法
/**
* 快速排序 — 三切4分法
* 速度排名:4/6
*
* @param array
* @param begin
* @param end
*/
public static void threeCut4Part(int[] array, int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
int equal = begin;//"相等区" 首位下标
int left = begin + 1;//"未知区" 首位下标
int right = end;//"未知区" 末位下标
int pivot = array[begin];//中枢,参考值
while (left <= right) {
if (pivot > array[left]) {
int temp = array[equal];
array[equal] = array[left];
array[left] = temp;
equal++;
left++;
} else if (pivot == array[left]) {
left++;
} else {//left值大于中枢
boolean stop = false;
while (pivot < array[right]) {
right--;
if (right < left) {
stop = true;
break;
}
}
if (stop) {
break;
}
if (pivot == array[right]) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
left++;
right--;
} else {//right值小于pivot
array[equal] = array[right];
array[right] = array[left];
array[left] = pivot;
equal++;
left++;
right--;
}
}
}
if (begin < equal - 1) {
threeCut4Part(array, begin, equal - 1);//排序 "小于区"
}
if (right + 1 < end) {
threeCut4Part(array, right + 1, end);//排序 "大于区"
}
}
6、双轴4分法
/**
* 快速排序 — 双轴4片法
* 执行速度排名:1/6
*
* @param array
* @param begin
* @param end
*/
public static void twoPivot(int[] array, int begin, int end) {
if (null == array || array.length < 2 || begin >= end) {
return;
}
if (array[begin] > array[end]) {
int temp = array[begin];
array[begin] = array[end];
array[end] = temp;
//中枢:左小右大
}
int pivot1 = array[begin];//小中枢,参考值
int pivot2 = array[end];//大中枢,参考值
int left = begin; // "小于区"末位下标
int middle = begin + 1;// "未知区" 首位下标
int right = end;// "大于区" 首位下标
while (middle < right) {
if (pivot1 > array[middle]) {//小于 "小中枢"
int temp = array[left + 1];
array[left + 1] = array[middle];
array[middle] = temp;
left++;
middle++;
} else if (pivot1 <= array[middle] && array[middle] <= pivot2) {// 大小中枢之间
middle++;
} else {//大于"大中枢"
boolean stop = false;
while (array[right - 1] > pivot2) {
right--;
if (right <= middle) {
stop = true;
break;
}
}
if (stop) {
break;
}
if (pivot1 <= array[right - 1] && array[right - 1] <= pivot2) {
int temp = array[right - 1];
array[right - 1] = array[middle];
array[middle] = temp;
middle++;
right--;
} else {// "未知区"首位大于pivot2,末位小于pivot1
int temp = array[right - 1];
array[right - 1] = array[middle];
array[middle] = array[left + 1];
array[left + 1] = temp;
left++;
middle++;
right--;
}
}
}
int temp = array[left];
array[left] = array[begin];
array[begin] = temp;
left--;
//↑ 调整"小中枢"的位置
temp = array[end];
array[end] = array[right];
array[right] = temp;
right++;
//↑ 调整"大中枢"的位置
if (begin < left) {
twoPivot(array, begin, left);//排序 "小于区"
}
if (left + 2 < right - 2) {
twoPivot(array, left + 2, right - 2);//排序 "中间区"
}
if (right < end) {
twoPivot(array, right, end);//排序 "大于区"
}
}
7、二分法(JS)
/**
* 二分法
* @param array
* @returns
*/
function binaryQuick(array) {
if (array.length <= 1) {
return array;
}
var index = Math.floor(array.length / 2);
var center = array.splice(index, 1)[0];
var left = [], right = [];
for (var i = 0; i < array.length; i++) {
array[i] < center ? left.push(array[i]) : right.push(array[i]);
}
return binaryQuick(left).concat([center], binaryQuick(right));
}
三、折半查找(二分查找)
/**
* 二分查找
* @param array 一维数组
* @param low 起始index(含)
* @param high 结束index(含)
* @param find 查找的值
* @returns find在数组的下标
*/
function binarySearch(array, low, high, find) {
if (low > high) {
return -1;
}
var mid = parseInt((high + low) / 2);
if (array[mid] == find) {
return mid;
} else if (array[mid] > find) {
high = mid - 1;
return binarySearch(array, low, high, find);
} else if (array[mid] < find) {
low = mid + 1;
return binarySearch(array, low, high, find);
}
}