数据结构基础加强之排序算法
冒泡排序-Bubble Sort
思想:做升序排列,通过相邻两数之间两两交换,让大的数先冒出来,到数组的尾部,小的数后冒出来。
图例:
排序之前:
第一次循环后:
代码实现:
public class BubbleSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
solution(array);
}
// 冒泡排序升序排列
private static void solution(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1; j++) {
if (array[j] > array[j + 1]) { // 相邻2个数比较如果前值大于后值则交换
swap(array, j + 1, j);
}
}
}
for (int i : array) {
System.out.print(i + " ");
}
}
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
插入排序 -Insert Sort
思想:每次将一个记录插入到已经排好序的有序表中,从而得到新的有序表。
将序列的第一个记录看成有序的子序列,从第二个记录开始逐个进行插入,直到整个序列有序。
图例:
排序之前:
第一次排序后:
因为数组第二个位置和第一个位置之间是有序的所以不变化。
第三次排序后:
第三个数和第二个交换,使前三个数有序。
代码实现:
public class InsertSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
solution(array);
}
// 插入排序升序排列
private static void solution(int[] array) {
for (int i = 1; i < array.length; i++) {
int cur = array[i];
int j = i - 1;
while (j >= 0) {
int k = j;
if (array[j] < cur) {
break;
} else {
array[++k] = array[j];
}
j--;
}
array[++j] = cur;
}
for (int i : array) {
System.out.print(i + " ");
}
}
}
选择排序 -Select Sort
思想:每次找一个最小值。放到数组的起始位置。
即从起始位置,每次循环选择未排序的第一个值作为哨兵,依次与后面的值比较,如果哨兵小,则两两交换,直至数组最后一个位置,此时哨兵位置的数为最小值。
图例:
排序之前:
第一次排序之后:
数组最后一个位置的值比第一个位置的小,两两交换,数组最小值放到第一个位置。
代码实现:
public class SelectSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
solution(array);
}
// 选择排序升序排列
private static void solution(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] > array[j]) {
swap(array, i, j);
}
}
}
for (int i : array) {
System.out.print(i + " ");
}
}
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
希尔排序 -Shell Sort
思想:对直接插入排序的改进,选择一个增量序列{size/2,t1,…..,1}。
根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序,依次减小增量,当增量因子为1时,整个序列作为一个表处理。
图例:
排序前:
第一次排序之后:因为数组长为9,所以初始增量为4
代码实现:
public class ShellSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
solution(array);
}
// 希尔排序实现升序排列
private static void solution(int[] array) {
int size = array.length;
for (int i = size / 2; i >= 1; i--) {
for (int j = 0; j < array.length; j++) {
if ((j + i) < array.length) {
if (array[j] > array[j + i]) {
swap(array, j, j + i);
}
}
}
}
for (int i : array) {
System.out.print(i + " ");
}
}
// 数组2个元素的交换
private static void swap(int[] array, int j, int i) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
归并排序 -Merge Sort
思想:使用分治法解决问题,每一次将数组对分,依次递归,直至每个数组只有一个元素,此时数组是有序的,然后将分开的数组,相邻两两之间合并,直至最后得到有序的数组。
图例:
代码实现:
public class MergeSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
int i = 0;
int j = array.length - 1;
solution(array, i, j);
for (int e : array) {
System.out.print(e + " ");
}
}
private static void solution(int[] array, int left, int right) {
int mid = (right + left) / 2;
if (left < right) {
solution(array, left, mid); // 左边
solution(array, mid + 1, right); // 右边
merge(array, left, mid, right);// 归并
}
}
// 归并实现升序排列
private static void merge(int[] array, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left;
int j = mid + 1;
int k = 0; // temp数组索引
while (i <= mid && j <= right) { // 填入2数组中较小的值
if (array[i] < array[j]) {
temp[k] = array[i];
k++;
i++;
} else {
temp[k] = array[j];
k++;
j++;
}
}
// 左边数组剩余填入
while (i <= mid) {
temp[k++] = array[i++];
}
// 右边数组剩余填入
while (j <= right) {
temp[k++] = array[j++];
}
for (int index = 0; index < temp.length; index++) {
array[index + left] = temp[index];
}
}
}
快速排序 -Quick Sort
思想:采用分治法,每次找一个基准值,对数组处理,让小于基准值的位于基准值的左边,大于基准值的位于基准值的右边。然后对左右两边做递归处理。
图例:每次取第一个值为基准值
排序之前:
第一次排序之后:
代码实现:
public class QuickSort {
public static void main(String[] args) {
int[] array = { 1, 9, 6, 8, 7, 3, 4, 2, 0 };
int low = 0;
int high = array.length - 1;
solution(array, low, high);
for (int i : array) {
System.out.print(i + " ");
}
}
// 递归实现升序快速排序
private static void solution(int[] array, int low, int high) {
if (low < high) {
int i = low;
int j = high;
int curr = array[i];
while (i < j) {
while (curr <= array[j] && i < j) {
j--;
}
if (i < j) {
array[i] = array[j];
i++;
}
while (curr >= array[i] && i < j) {
i++;
}
if (i < j) {
array[j] = array[i];
j--;
}
}
array[i] = curr;
solution(array, low, i - 1);
solution(array, i + 1, high);
}
}
}
基数排序-Radix Sort
思想:桶排序的一种。让个位、十位、百位的大小依次对数组进行排序。
图例:
代码实现:
public class RadixSort {
public static void main(String[] args) {
int[] array = { 11, 911, 6343, 834, 77, 3345, 49986, 21, 0 };
solution(array);
for (int i : array) {
System.out.print(i + " ");
}
}
private static void solution(int[] array) {
int maxPos = getMaxPos(array);
int[][] temp = new int[10][array.length + 1]; // 临时数组 按元素位 上的数值大小 依次存储元素
for (int i = 0; i < temp.length; i++) {
temp[i][0] = 0; // 记录行内元素的个数 初始化为0
}
for (int pos = 1; pos < maxPos; pos++) {
for (int index = 0; index < array.length; index++) {
int row = getPos(array[index], pos);
int col = ++temp[row][0];
temp[row][col] = array[index];
}
// 收集元素
for (int row = 0, i = 0; row < 10; row++) {
for (int col = 1; col <= temp[row][0]; col++) {
array[i++] = temp[row][col];
}
temp[row][0] = 0; // 恢复行元素数记录 下次继续使用
}
}
}
// 取出数组元素在当前Pos上的数 pos = 1:个位 pos = 2:十位...
private static int getPos(int cur, int pos) {
int temp = 1;
for (int i = 0; i < pos - 1; i++) {
temp = temp * 10;
}
return (cur / temp) % 10;
}
// 得到数组中最大元素的位数
private static int getMaxPos(int[] array) {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (max < array[i]) {
max = array[i];
}
}
int result = 1;
int temp = 1;
while (true) {
temp = temp * 10;
if (max / temp != 0) {
result++;
} else {
break;
}
}
return result;
}
}
堆排序 -Heap Sort
基本思想:基于最小堆或者最大堆。对给定的数组建立堆,依据堆对数组排序
具体说明可以参考:http://blog.youkuaiyun.com/a815060271/article/details/72328745
各个排序算法之间的比较
各排序算法稳定性,时间复杂度,空间复杂度分析:
具体代码可以参考:https://github.com/Li-JY/algorithm-and-datastructure/tree/master/src/sort