1. 冒泡排序
①、算法描述:
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
- 对每一对相邻元素做同样的工作,第一轮使尾部值最大,第二轮尾部两个值最大。
- 针对所有的元素重复以上的步骤;
②、代码实现:
public static void bubbleSort(int[] list) {
boolean needswap = true;
for(int i = 1; i < list.length && needswap; i++){
needswap = false;
for(int j = 0; j < list.length - i; j++){
if(list[j] > list[j + 1]){
int tmp = list[j];
list[j] = list[j + 1];
list[j + 1] = tmp;
needswap = true;
}
}
}
}
2、选择排序(Selection Sort)
①、算法描述:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾(即与未排序序列的第一个交换)。以此类推,直到所有元素均排序完毕。
②、代码实现
public static void selectSort(int[] list) {
if(list.length == 0) return;
for(int i = 0; i < list.length; i++) {
int maxIndex = i;
for(int j = i; j < list.length; j++) {
if(list[j] < list[maxIndex]) {
maxIndex = j;
}
}
int tmp = list[maxIndex];
list[maxIndex] = list[i];
list[i] = tmp;
}
}
3. 插入排序
①、算法描述:
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到已排序元素小于/等于新元素的位置;将新元素插入到该位置;
- 重复步骤2~5。
②、代码实现
public void insertSort(int[] list){
for(int i = 1; i < list.length; i++){
int pos = list[i];
int index = i - 1;
while(index >= 0 && list[index] > pos){
list[index + 1] = list[index];
index--;
}
list[index + 1] = pos;
}
}
4、希尔排序(Shell Sort)
①、算法描述:
-
选择一个增量序列, eg: 4, 2, 1;
-
每趟排序,根据对应的增量,将待排序列分割成若干长度的子序列,分别对各子表进行直接插入排序。
②、代码实现:
public void shellSort(int[] array){
int len = array.length;
int gap = len / 2;
while(gap > 0){
for(int i = gap; i < len; i++){
int tmp = array[i];
int index = i - gap;
while(index >= 0 && array[index] > tmp){
array[index + gap] = array[index];
index -= gap;
}
array[index + gap] = tmp;
}
gap /= 2;
}
}
5、归并排序(Merge Sort)
①、算法描述:
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
②、代码实现:
private int[] tmp ;
public static void mergeSort(int[] list) {
tmp = new int[list.length];
mergeSort(list, 0, list.length-1);
}
public static void mergeSort(int[] a,int start,int end){
if(start < end){//当子序列中只有一个元素时结束递归
int mid = (start + end)/2;
mergeSort(a, start, mid);
mergeSort(a, mid + 1, end);
merge(a, start, mid, end);//合并
}
}
public static void merge(int[] a,int left,int mid,int right){
int p1 = left, p2 = mid + 1, k = left;//p1、p2是检测指针,k是存放指针
while(p1 <= mid || p2 <= right){
if(p1 > mid)
tmp[k++] = a[p2++];
else if(p2 > right)
tmp[k++] = a[p1++];
else if(a[p1] <= a[p2])
tmp[k++] = a[p1++];
else
tmp[k++] = a[p2++];
}
for (int i = left; i <= right; i++)
a[i] = tmp[i];
}
6、快速排序(Quick Sort)
①、算法描述:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。
- 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
②、代码实现:递归
public void quickSort(int[] list, int start, int end){
if(start > end) return;
int index = partition(list, start, end);
quickSort(list, start, index - 1);
quickSort(list, index + 1, end);
}
public int partition(int[] List, int start, int end){
int pivot = list[start];
int i = start, j = end;
while(i < j){
while(i < j && list[j] >= pivot) j--;
list[i] = list[j];
while(i <j && list[i] < pivot) i++;
list[j] = list[i];
}
list[i] = pivot;
return i;
}
非递归实现:
public void quickSort(int[] array,int start, int end){
Stack<Integer> stack = new Stack<>();
stack.push(start);
stack.push(end);
while(!stack.isEmpty()){
int right = stack.pop();
int left = stack.pop();
int index = partition(array, left, right);
if(index - 1 > left){
stack.push(left);
stack.push(index - 1);
}
if(index +1 < right){
stack.push(index +1);
stack.push(right);
}
}
}
7、堆排序:堆排序的时间复杂度是O(N*lgN)。
堆排序构建堆的时间复杂度是N, 重调堆的时间复杂度是logN
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
用数组实现二叉堆有如下性质:
性质一:索引为i的左孩子的索引是 (2i+1);
性质二:索引为i的左孩子的索引是 (2i+2);
性质三:索引为i的父结点的索引是 floor((i-1)/2);
①、算法描述:
- 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
- 将其与末尾元素进行交换,此时末尾就为最大值。
- 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
- 如此反复执行,便能得到一个有序序列了。
②、代码实现:
public void heapSort(int[] arr){
if(arr == null || arr.length == 0) return;
for(int i = arr.length / 2 - 1; i >= 0; i--){
adjustHeap(arr, i, arr.length - 1);
}
for(int j = arr.length - 1; j > 0; j--){
swap(arr, 0, j);
adjustHeap(arr, 0, j - 1);
}
}
public void adjustHeap(int[] arr, int start, int end){
int tmp = arr[start]; // 当前(current)节点的大小
for (int k = 2*start + 1; k <= end; k = 2 * k + 1){
if (k < end && arr[k] < arr[k + 1])
k++; // 左右两孩子中选择较大者
if (tmp >= arr[k]) break; // 调整结束
else{ // 交换值
arr[start] = a[k];
arr[k] = tmp;
}
start = k;
}
}
8、计数排序(Counting Sort):适用于数据比较密集的情况
①、算法描述:
- 根据待排序集合中最大元素和最小元素的差值范围,申请额外空间;
- 遍历集合,将每个元素出现的次数记录到对应的额外空间内(index=元素值-min);
- 填充目标数组:因额外空间存放这每个元素的次数,每填充一个,将对应次数减一
②、代码实现:
public int[] countSort(int[] array){
if(array.length == 0) return array;
int max = array[0], min = array[0];
for(int i = 1; i < array.length; i++){
if(array[i] > max)
max = array[i];
if(array[i] < min)
min = array[i];
}
int[] bucket = new int[max - min + 1];
for(int i = 0; i <array.length; i++)
bucket[array[i] - min]++;
int index = 0, i = 0;
while(index < array.length){
if(bucket[i] != 0){
array[index++] = i + min;
bucket[i]--;
}else
i++;
}
return array;
}
9、桶排序(Bucket Sort)
①、算法描述:
- 设置一个定量的数组当作空桶;
- 遍历输入数据,并且把数据一个一个放到对应的桶里去;
- 对每个不是空的桶进行排序;
- 从不是空的桶里把排好序的数据拼接起来。
②、代码实现:
public static void bucketSort(int[] arr){
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int bucketNum = (max - min) / arr.length + 1; //桶数
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for(int i = 0; i < bucketNum; i++){
bucketArr.add(new ArrayList<Integer>());
}
for(int i = 0; i < arr.length; i++){ //将元素入桶
int index = (arr[i] - min) / arr.length;
bucket.get(index).add(arr[i]);
}
for(int i = 0; i < bucket.length; i++){ //对各个桶排序
Collection.sort(bucket[i]);
}
}
10、基数排序(Radix Sort)
①、算法描述:
- 取得数组中的最大数,并取得位数;
- arr为原始数组,从最低位开始按照每一位的大小进行排序;
- 常常利用桶排序,每一轮生成10个桶,位数大小对应桶的位置
②、代码实现:
public static int[] RadixSort(int[] array) {
if (array == null || array.length < 2)
return array;
int max = array[0];
for(int i = 1; i <array.length; i++)
max = Math.max(max, array[i]);
int cnt = 0;
while(max != 0){
max /= 10;
cnt++;
}
int mod = 10, div = 1;
ArrayList<ArrayList<Integer>> bucket = new
ArrayList<ArrayList<Integer>>();
for (int i = 0; i < 10; i++)
bucket.add(new ArrayList<Integer>());
for(int i = 0; i < cnt; i++){
for(int j = 0; j < array.length; j++){
int num = (array[j] % mod) / div;
bucket.get(num).add(array[i]);
}
int index = 0;
for(int j = 0; j < bucket.size(); j++){
for(int k = 0; k < bucket.get(j).size(); k++){
array[index++] = bucket.get(j).get(k);
}
bucket.get(j).clear();
}
mod *= 10;
div *= 10;
}
return array;
}