/**
* 快速排序
* @param arrays
* @param left
* @param right
*/
public static void quickSort(int arrays[], int left, int right) {
int dp;
if (left < right) {
dp = partition(arrays, left, right);
quickSort(arrays, left, dp - 1);
quickSort(arrays, dp + 1, right);
}
}
private static int partition(int arrays[], int left, int right) {
int pivot = arrays[left];
while (left < right) {
while (left < right && arrays[right] >= pivot)
right--;
if (left < right)
arrays[left++] = arrays[right];
while (left < right && arrays[left] <= pivot)
left++;
if (left < right)
arrays[right--] = arrays[left];
}
arrays[left] = pivot;
return left;
}
步骤为:
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
引用维基百科的图片和解释步骤
/**
* 冒泡排序
* @param arrays
* @return
*/
public static int[] bubbleSort(int[] arrays) {
for (int i=0; i<arrays.length-2; i++) {
for (int j=i+1; j<arrays.length; j++) {
if (arrays[j] < arrays[i]) {
int temp = arrays[j];
arrays[j] = arrays[i];
arrays[i] = temp;
}
}
}
return arrays;
}
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
/**
* 插入排序
* @param arrays
* @return
*/
public static int[] insertSort(int[] arrays) {
int i, j;
for (i=1; i<arrays.length; i++) {
int temp = arrays[i];
for (j=i-1; j>=0 && arrays[j]>temp; j--)
arrays[j+1] = arrays[j];
arrays[j] = temp;
}
return arrays;
}
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
如果比较操作 代价比 交换操作 大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找插入排序。
/**
* 归并排序
* 递归算法
* @param arrays
* @return
*/
public static void mergingSort(int[] arrays, int start, int end) {
int[] reg = new int[arrays.length];
int len = end - start;
if (len <= 1)
return;
int mid = (len >> 1) + start; //位运算,有符号右移 1 位, 相当于len/2
//位运算 左移1位相当于 乘以2,右移1位相当于除以2
int startLeft = start, endLeft = mid;
int startRight = mid+1, endRight = end;
mergingSort(arrays, startLeft, endLeft);
mergingSort(arrays, startRight, endRight);
int k = start;
while (startLeft <= endLeft && startRight <= endRight) {
reg[k ++] = arrays[startLeft] < arrays[startRight] ? arrays[startLeft ++] : arrays[startRight ++];
}
while (startLeft <= endLeft) {
reg[k++] = arrays[startLeft++];
}
while (startRight <= endRight) {
reg[k++] = arrays[startRight++];
}
for (int i=start; i<end; i++) {
arrays[i] = reg[i];
}
return ;
}
- 将序列每相邻两个数字进行归并操作,形成
个序列,排序后每个序列包含两个元素
- 将上述序列再次归并,形成
个序列,每个序列包含四个元素
- 重复步骤2,直到所有元素排序完毕
/**
* 希尔排序
* @param arrays
* @return
*/
public static int[] shellSort(int[] arrays) {
int gap = 1, i, j, len = arrays.length;
int temp;
while (gap < len / 3)
gap = gap * 3 + 1; // <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...
for (; gap > 0; gap /= 3)
for (i = gap; i < len; i++) {
temp = arrays[i];
for (j = i - gap; j >= 0 && arrays[j] > temp; j -= gap)
arrays[j + gap] = arrays[j];
arrays[j + gap] = temp;
}
return arrays;
}
例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:
13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10
然后我们对每列进行排序:
10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45
将上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:
10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45
排序之后变为:
10 14 13 25 23 33 27 25 59 39 65 73 45 94 82 94
最后以1步长进行排序(此时就是简单的插入排序了)。