以前看了一点关于数据结构和算法的文章,这是个充满魅力的领域,想简单总结分享一下java
从小到大:算法
冒泡的特色:每一次轮回后(步骤4),末排序的值都会“冒”到正确的位置,而后继续轮回,继续冒泡;数组
冒泡实战:数据结构
public static int[] bubbleSort(int[] arr) {
// 初始化第一次最终冒泡的位置,及最后一个索引
int lastSortedIndex = arr.length-1;
// 初始化设定为排序
boolean sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0; i < lastSortedIndex; i++) {
if (arr[i] > arr[i + 1]) {
sorted = false;
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
lastSortedIndex--;
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(bubbleSort(arr))); // 1,2,3,4,5
}
复制代码
冒泡的效率:数据结构和算法
比较:(N-1)+(N-2)+(N-3)+...+1ui
交换:最坏:(N-1)+(N-2)+(N-3)+...+1,最好:0spa
时间复杂度:O(N²)指针
从小到大:code
选择特色:选择最小值索引。比较时,只记录索引值,不作置位操做,直到本次数组比较完毕,再进行至多一次交换,最小值将依次向后排列排序
选择实战:
public static int[] selectionSort(int[] arr) {
// 从小到大排序,依次最小的值
for (int i = 0; i < arr.length; i++) {
// 初始化最小值的索引
int minIdenx = i;
for (int j = i+1; j < arr.length; j++) {
// 当前索引值小于当前最小值,更新索引
if (arr[j] < arr[minIdenx]) {
minIdenx = j;
}
}
// 当前最小值的索引不在起点
if (minIdenx != i) {
int temp = arr[i];
arr[i] = arr[minIdenx];
arr[minIdenx] = temp;
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(selectionSort(arr)));
}
复制代码
选择效率:
比较:(N-1)+(N-2)+(N-3)+...+1
交换:最多:N-1,最少:0(每轮1或0次)
时间复杂度:O(N²/2) ——>忽略常数——>O(N²)
选择排序的步数大概只有冒泡的一半
从小到大:
插入特色:每轮四个步骤,移出,比较,平移,插入
插入实战:
public static int[] insertionSort(int[] arr) {
// 从第二个元素开始移出
for (int i = 1; i < arr.length; i++) {
// 初始空隙所在位置的指针
int position = i;
// 当前移出值保存到临时变量
int tempValue = arr[i];
// 直到空隙移到最左侧,或当前值小于临时变量,则将临时变量插入空隙
while (position > 0 && arr[position - 1] > tempValue) {
// 不符合条件,将左侧值右移一位,即:将左侧的值赋给右侧,指针减一
arr[position] = arr[--position];
}
// 临时变量插入当前空隙的指针
arr[position] = tempValue;
}
return arr;
}
public static void main(String[] args) {
int[] arr = {2, 3, 1, 5, 4};
System.out.println(Arrays.toString(insertionSort(arr)));
}
复制代码
插入效率:
移出:N-1
比较:最多:1+2+3+...+N-1=N²/2,最少:N-1
平移:最多:N²/2,最少:0(有序)
插入:N-1
时间复杂度:O(N²+2N-2)——>简化——>O(N²),最坏、平均、最好状况:N二、N2/二、N步
分区:
从小到大:
快速特色:一次分区至少有N次比较,及数组的每一个值都要与轴作比较;每次分区,左右指针豆花从两端开始靠近,直到相遇
实战:
public class TestQuickSort {
public static int partition(int[] arr, int leftPointer, int rightPointer) {
// 老是取最右的值做为轴
int pivotPosition = rightPointer;
int pivot = arr[pivotPosition];
// 将右指针指向轴左边的一格
rightPointer -= 1;
while (true) {
// 左指针只要小于轴,右移,不能超过轴
while (arr[leftPointer] < pivot && leftPointer < pivotPosition) {
leftPointer += 1;
}
// 右指针只要小于轴,左移
while (arr[rightPointer] > pivot && rightPointer > 0) {
rightPointer -= 1;
}
if (leftPointer >= rightPointer) {
break;
} else {
swap(arr, leftPointer, rightPointer);
}
}
// 将左指针的值与轴交换
swap(arr, leftPointer, pivotPosition);
// 返回左指针
return leftPointer;
}
public static void swap(int[] arr, int pointer1, int pointer2) {
int tempValue = arr[pointer1];
arr[pointer1] = arr[pointer2];
arr[pointer2] = tempValue;
}
public static int[] quickSort(int[] arr, int leftPointer, int rightPointer) {
// 基准情形:分出的子数组长度为0或1
if (rightPointer - leftPointer <= 0) {
return arr;
}
// 将数组分红两部分,并返回分隔所用的轴的索引
int pivotPosition = partition(arr, leftPointer, rightPointer);
// 对轴左侧的部分递归调用quicksort
quickSort(arr, leftPointer, pivotPosition - 1);
// 对轴右侧的部分递归调用quicksort
quickSort(arr, pivotPosition + 1, rightPointer);
return arr;
}
public static void main(String[] args) {
// int[] arr = {0, 5, 2, 1, 6, 4};
int[] arr = {5, 6, 0, 4, 3, 2, 1, 4};
int[] sort = quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(sort));
}
}
复制代码
快速效率:
比较:每一个值都要与轴比较
交换:在适当时候将左右指针所指的两个值交换位置
时间复杂度:一次分区,最少交换1次,最多N/2次,分区——>O(N);总共——>O(NlogN) 最好:O(NlogN),平均O(NlogN),最坏O(N²)(每次分区都是轴落在数组的开头或结尾,如已升序或降序)
参考书籍:数据结构与算法图解-【美】杰伊·温格罗