一、前言
1.1、前言
此博客虽然为转载,但代码大部分都是我自己写的,加上了自己的一些思路和注解,希望大家能喜欢,点个赞再走呗,多谢!!
1.2、复杂度
1.3、算法稳定性
排序算法的稳定性大家应该都知道,通俗地讲就是能保证排序前两个相等的数据其在序列中的先后位置顺序与排序后它们两个先后位置顺序相同。即:如,如果A i == A j,Ai 原来在 Aj 位置前,排序后 Ai 仍然是在 Aj 位置前。
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法
冒泡排序、插入排序、归并排序和基数排序都是稳定的排序算法
二、冒泡排序
2.1、思路:
1 、比较相邻的元素,如果第一个比第二个大,就交换它们两个; 2、对每一对相邻元素作相同的工作,从开始第一对到结尾的最后一对,这样在最后的元素就是最大的数; 3、排除最大的数,解这下一轮继续相同的操作,确定第二大的数… 3、重复步骤1-3,直到排序完成。
2.2、动画演示:
2.3、实现代码
package com.chan.sort;
public class BubbleSort {
private static int[] sort(int[] a) {
for (int i = 0; i <a.length; i++) {
for (int j = 0; j < a.length-i-1; j++) {
if (a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j + 1];
a[j+1] = temp;
}
}
}
return a;
}
private static void print(int[] a){
for (int i : a) {
System.out.print(" "+i);
}
System.out.println();
}
public static void main(String[] args) {
int[] a = {6,1, 2, 5, 3, 4};
print(a);
sort(a);
print(a);
}
}
结果:
6 1 2 5 3 4
1 2 3 4 5 6
2.4、总结
平均时间复杂度:O(n2) 空间复杂度:O(1) 算法稳定性:稳定
三、插入排序
3.1、思路
1、从第一个元素开始,该元素可以认为已经被排序; 2、取出下一个元素,在前面已排序的元素序列中向前扫描; 3、如果该元素(以拍下)大于新元素,将该元素移动下一位置; 4、重复不走3、直到找到已排序的元素小于或者等于新元素的位置; 5、将新元素插入到该位置后; 6、重复步骤2-5。
3.2、动画演示
3.3、实现代码
package com.chan.sort;
public class InsertSort {
private static int[] sort(int[] a) {
for (int i = 1; i < a.length; i++) {
int temp = a[i];
int j = i-1;
for (; j >= 0; j--) {
if (a[j] > temp) {
a[j + 1] = a[j];
}else {
break;
}
}
a[j+1] = temp;
}
return a;
}
private static void print(int[] a) {
for (int i : a) {
System.out.print(" " + i);
}
System.out.println();
}
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
print(a);
sort(a);
print(a);
}
}
结果:和冒泡一致,后不再展示结果。
3.4、总结
平均时间复杂度:O(n2) 空间复杂度:O(1) 算法稳定性:稳定
四、选择排序
4.1、思路
1、第一轮,找到最小的元素,和数组第一个数交换位置 2、第N(N<n)轮,找到第二小的元素,和数组第N(N<n)个数交换位置 3、直到最后一个(n)元素,排序完成
4.2、动画演示
4.3、实现代码
package com.chan.sort;
public class SelectSort {
public static int[] sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
if (min != i){
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
return a;
}
public static void print(int[] a) {
for (int i : a) {
System.out.print(" " + i);
}
System.out.println();
}
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
print(a);
sort(a);
print(a);
}
}
4.4、总结
平均时间复杂度:O(n2) 算法空间复杂度:O(1) 算法稳定性:不稳定
五、希尔排序
5.1、思路
1、把数组分割成若干(h)个小组(一般数组长度length/2),然后对每个小组分别进行插入排序; 2、每一轮分割的小组的个数逐步缩小,h/2->h/4->h/8,并且进行排序,保证有序。当h=1时,则数组排序完成
5.2、动画演示
5.3、实现代码
package com.chan.sort;
public class ShellSort extends SelectSort{
public static int[] sort(int[] a) {
int gap = a.length /2;
while (gap>0){
for (int i = gap; i < a.length; i++) {
int temp = a[i];
int index = i - gap;
while (index >=0 && a[index] > temp){
a[index + gap] = a[index];
index -= gap;
}
a[index + gap] = temp;
}
gap /=2;
}
return a;
}
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
print(a);
sort(a);
print(a);
}
}
5.4、总结
平均时间复杂度:O(nlogn) 算法空间复杂度:O(1) 算法稳定性:稳定
六、快速排序
6.1、思路
快排,面试最喜欢问的排序算法,这是运用分治法的一种排序算法
1、从数组中选一个数作为基准值,一般选第一个数,或者最后一个数 2、采用双指针(头尾两端)遍历,从左往右找到比基准值大的第一个数,从右往左找到比基准值小的第一个数,交换两数位置,直到头尾指针相等或头指针大于尾指针,把基准值与头指针的数交换。这样一轮之后,左边的数就比基准值小,右边的数就比基准值大 3、对左边的数列,重复上面1,2不走。对右边重复1,2步骤 左右两边数列递归结束后,排序完成(即递归左边数据为1位或右边数据为1位)
6.2、动画演示
6.3、实现代码
package com.chan.sort;
public class QuickSort extends SelectSort {
public static void sort(int[] a, int start, int end) {
if (start > end) {
return;
}
int temp = a[start];
int i = start + 1, j = end;
while (i < j) {
while (i < j && a[i] < temp) {
i++;
}
while (i < j && a[j] > temp) {
j--;
}
if (i < j) {
int item = a[i];
a[i] = a[j];
a[j] = item;
}
}
if (i <= end && j >= start) {
a[start] = a[j];
a[j] = temp;
sort(a, start, i - 1);
sort(a, i + 1, end);
}
}
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
print(a);
sort(a, 0, a.length - 1);
print(a);
}
}
5.4、总结
平均时间复杂度:O(nlogn) 算法空间复杂度:O(1) 算法稳定性:不稳定
七、归并排序
7.1、思路
归并排序是也是采用分治法,并且是一种稳动的排序方式,不过需要使用到额外的空间
1、把数组不断划分成子序列,划成长度职业2或者1的子序列 2、然后利用临时数组,对子序列进行排序,合并,再把临时数组的值赋值回原数组 3、反复操作1~2步骤,直到排序完成 注意:只有"相邻同一组"的数组可以进行比较,我这句话会在代码中显现
7.2、动画演示
7.3、实现代码
package com.chan.sort;
import java.util.Arrays;
public class MergeSort extends SelectSort {
public static void sort1(int[] a, int[] b, int start, int end) {
if (start >= end) {
return;
}
int mid = (start + end) / 2;
sort1(a, b, start, mid);
sort1(a, b, mid + 1, end);
sort2(a, b, start, mid, end);
}
public static void sort2(int[] a, int[] b, int start, int mid, int end) {
int index = 0;
int i = start;
int j = mid + 1;
while (i <= mid && j <= end) {
if (a[i] < a[j]) {
b[index++] = a[i++];
} else {
b[index++] = a[j++];
}
}
while (i <= mid) {
b[index++] = a[i++];
}
while (j <= end) {
b[index++] = a[j++];
}
System.arraycopy(b, 0, a, start, index);
}
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
int[] b = new int[a.length];
print(a);
sort1(a, b, 0, a.length - 1);
print(a);
}
}
7.4、总结
平均时间复杂度:O(nlogn) 算法空间复杂度:O(n) 算法稳定性:稳定
八、堆排序
8.1、思路
大顶堆概念:每个节点的值都大于或者等于它的左右子节点的值,所以顶点的数就是最大值
8.2、动画演示
8.3、实现代码
package com.chan.sort;
public class HeapSort {
public static void main(String[] args) {
int[] a = {6, 1, 2, 5, 3, 4};
sort(a);
for (int i : a) {
System.out.print(" " + i);
}
System.out.println();
}
protected static void sort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
heapSort(nums);
}
private static void heapSort(int[] nums) {
if (nums == null || nums.length < 2) {
return;
}
createTopHeap(nums);
int size = nums.length;
while (size > 1) {
swap(nums, 0, size - 1);
size--;
updateHeap(nums, size);
}
}
private static void createTopHeap(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int currIndex = i;
int parentIndex = (currIndex - 1) / 2;
while (nums[currIndex] > nums[parentIndex]) {
swap(nums, currIndex, parentIndex);
currIndex = parentIndex;
parentIndex = (currIndex - 1) / 2;
}
}
}
private static void updateHeap(int[] nums, int size) {
int index = 0;
int left = 2 * index + 1;
int right = 2 * index + 2;
while (left < size) {
int largestIndex;
if (right < size && nums[left] < nums[right]) {
largestIndex = right;
} else {
largestIndex = left;
}
if (nums[index] > nums[largestIndex]) {
largestIndex = index;
}
if (largestIndex == index) {
break;
}
swap(nums, largestIndex, index);
index = largestIndex;
left = 2 * index + 1;
right = 2 * index + 2;
}
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
8.4、总结
平均时间复杂度:O(nlogn) 算法空间复杂度:O(n) 算法稳定性:不稳定
九、基数排序
9.1、思路
基数排序是一种非比较型整数排序算法
1、将整数按位数切割成不同的数字 2、然后按每个位数分别比较。 3、由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。
9.2、动画演示
9.3、实现代码
package com.chan.sort;
import java.util.Arrays;
public class RadixSort{
public static void main(String[] args){
int[] a = {6, 1, 2, 5, 3, 4};
int[] sort = sort(a);
for (int i : sort) {
System.out.print(" " + i);
}
}
public static int[] sort(int[] sourceArray) {
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int maxDigit = getMaxDigit(arr);
return radixSort(arr, maxDigit);
}
private static int getMaxDigit(int[] arr) {
int maxValue = getMaxValue(arr);
return getNumLenght(maxValue);
}
private static int getMaxValue(int[] arr) {
int maxValue = arr[0];
for (int value : arr) {
if (maxValue < value) {
maxValue = value;
}
}
return maxValue;
}
protected static int getNumLenght(long num) {
if (num == 0) {
return 1;
}
int lenght = 0;
for (long temp = num; temp != 0; temp /= 10) {
lenght++;
}
return lenght;
}
private static int[] radixSort(int[] arr, int maxDigit) {
int mod = 10;
int dev = 1;
for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
int[][] counter = new int[mod * 2][0];
for (int j = 0; j < arr.length; j++) {
int bucket = ((arr[j] % mod) / dev) + mod;
counter[bucket] = arrayAppend(counter[bucket], arr[j]);
}
int pos = 0;
for (int[] bucket : counter) {
for (int value : bucket) {
arr[pos++] = value;
}
}
}
return arr;
}
private static int[] arrayAppend(int[] arr, int value) {
arr = Arrays.copyOf(arr, arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
9.4、总结
平均时间复杂度:O(p(n+b)) 算法空间复杂度:O(p(n+b)) 算法稳定性:稳定
十、gitee源码
我的gitee源码链接
|