冒泡排序:
比较相邻的两个数据,如果第二个数小,就交换位置
平均时间复杂度:O(n^2)
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {4,1,8,2,6};
for(int i =0;i<arr.length;i++){
for(int j = 0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1]=temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
选择排序:
在长度为N的数组中,第一次遍历n-i个数,找到最小的数值与第i个元素交换
平均时间复杂度:O(n^2)
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] arr = {1,4,8,2,6};
for(int i =0;i<arr.length-1;i++){
int min = i;
for(int j = i+1;j<arr.length;j++){
if(arr[min] >arr[j]){
min = j;
}
}
if(min!=i){
int temp= arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
插入排序:
在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
平均时间复杂度:O(n^2)
import java.util.Arrays;
public class InsertSort {
public static void main(String[] args) {
int[] arr = {4,1,8,2,6};
for(int i=1; i<arr.length; i++){
for(int j=i; j>0; j--){
if(arr[j]<arr[j-1]){
int temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
希尔排序:
在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {1,4,8,2,6};;
for(int i = arr.length/2;i>0;i=i/2){
for(int j = i;j<arr.length;j++){
int k = j-i;
while(k>=0&&arr[k]>arr[k+i]){
int temp = arr[k];
arr[k] = arr[k+i];
arr[k+i] = temp;
k=k-i;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序:
对于给定的一组记录,选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分,直到序列中的所有记录均有序为止。
时间复杂度:
import java.util.Arrays;
class QuickSort {
public static void main(String[] args) {
int arr[] = {4,1,8,2,6};
quickSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int arr[], int low, int hight) {
int i, j, index;
if (low > hight) {
return;
}
i = low;
j = hight;
index = arr[i]; // 用子表的第一个记录做基准
while (i < j) { // 从表的两端交替向中间扫描
while (i < j && arr[j] >= index)
j--;
if (i < j)
arr[i++] = arr[j];// 用比基准小的记录替换低位记录
while (i < j && arr[i] < index)
i++;
if (i < j) // 用比基准大的记录替换高位记录
arr[j--] = arr[i];
}
arr[i] = index;// 将基准数值替换回 a[i]
sort(arr, low, i - 1); // 对低子表进行递归排序
sort(arr, i + 1, hight); // 对高子表进行递归排序
}
public static void quickSort(int arr[]) {
sort(arr, 0, arr.length - 1);
}
}
归并排序:
将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。
时间复杂度:nlogn
import java.util.Arrays;
public class mergeSort {
public static void main(String[] args) {
int[] arr = {4,1,8,2,6};
int[] tmp = new int[arr.length]; //新建一个临时数组存放
mergeSort(arr,0,arr.length-1,tmp);
System.out.println(Arrays.toString(arr));
}
public static void merge(int[] arr,int low,int mid,int high,int[] tmp){
int i = 0;
int j = low;
int k = mid+1; //左边序列和右边序列起始索引
while(j <= mid && k <= high){
if(arr[j] < arr[k]){
tmp[i++] = arr[j++];
}else{
tmp[i++] = arr[k++];
}
}
//若左边序列还有剩余,则将其全部拷贝进tmp[]中
while(j <= mid){
tmp[i++] = arr[j++];
}
while(k <= high){
tmp[i++] = arr[k++];
}
for(int t=0;t<i;t++){
arr[low+t] = tmp[t];
}
}
public static void mergeSort(int[] arr,int low,int high,int[] tmp){
if(low<high){
int mid = (low+high)/2;
mergeSort(arr,low,mid,tmp); //对左边序列进行归并排序
mergeSort(arr,mid+1,high,tmp); //对右边序列进行归并排序
merge(arr,low,mid,high,tmp); //合并两个有序序列
}
}
}
基数排序:
将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
时间复杂度:o(n)
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void radixSort(int[] arr) {
//待排序列最大值
int max = arr[0];
int exp;//指数
//计算最大值
for (int anArr : arr) {
if (anArr > max) {
max = anArr;
}
}
//从个位开始,对数组进行排序
for (exp = 1; max / exp > 0; exp *= 10) {
//存储待排元素的临时数组
int[] temp = new int[arr.length];
//分桶个数
int[] buckets = new int[10];
//将数据出现的次数存储在buckets中
for (int value : arr) {
//(value / exp) % 10 :value的最底位(个位)
buckets[(value / exp) % 10]++;
}
//更改buckets[i],
for (int i = 1; i < 10; i++) {
buckets[i] += buckets[i - 1];
}
//将数据存储到临时数组temp中
for (int i = arr.length - 1; i >= 0; i--) {
temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
buckets[(arr[i] / exp) % 10]--;
}
//将有序元素temp赋给arr
System.arraycopy(temp, 0, arr, 0, arr.length);
}
}
}
堆排序:
以构建最大堆为例,堆排序的过程:
1、原始数组形成一个顺序堆。数组中下标索引为i的节点,左节点是i2 +1,右节点是i2+2
2、初始化堆,从最后一个叶子节点的父节点开始一层层向上遍历,使得每一对父子节点中的最大节点上浮,维持最大堆的性质。
如果有交换位置的操作,那么要以交换后的新子节点为父节点递归遍历,以维持该分支上的最大堆性质。
直到遍历到根节点,此时根节点最大。
3、排序阶段:将根节点与最后一个叶子节点交换位置,交换过位置的尾部叶子节点就是从小到大的排序,最后的叶子节点的索引相对应也减1。
然后以根节点,维护最大堆性质,同样的,如果有交换位置的操作,那么要以被交换的子节点为父节点递归遍历,以维持该分支上的最大堆性质
个人认为,堆排序的核心点在于:如果有交换位置的操作,那么要以交换后的新子节点为父节点递归遍历,以维持该分支上的最大堆性质
时间复杂度:O(nlogn)
import java.util.Arrays;
class HeapSort {
public static void main(String []args){
int[] arr = {4,1,8,2,6};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int []arr){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构+交换堆顶元素与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素与末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素i
for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
k++;
}
if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
}else{
break;
}
}
arr[i] = temp;//将temp值放到最终的位置
}
public static void swap(int []arr,int a ,int b){
int temp=arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}