冒泡排序,选择排序,插入排序(直接插入,二分插入,希尔排序),快速排序,堆排序,归并排序,计数排序,桶排序,基数排序。
冒泡排序:
基本思想是:两两比较相邻记录的关键字,如果反序则交换
public class BubbleSort {
public static void main(String[] args) {
int a[] ={345,54,66,3,76,345,7,4,3} ;
for(int i=0;i for(int j=0;j if(a[j]>a[j+1]){ int temp; temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } } } 算法思想:将待排序序列分为两部分,一部分为有序序列,另一部分为无序序列。第一趟:从a[0]到a[n-1]中找到最小的数a[i],然后将a[i]与a[0]交换,第二趟:从a[1]到a[n-1]中找到最小的数a[j],然后将a[j]与a[1]交换,第三趟:从a[2]到a[n-1]中找到最小的数a[k],然后将a[k]与a[2]交换 …… public class SelectSort { public static void main(String[] args) { int a[] ={345,54,66,3,76,345,7,4,3} ; for(int i = 0;i int min = a[i]; for(int j = i+1;j if(min>a[j]){ int temp; temp = min; min = a[j]; a[j] = temp; } } a[i] = min; } } } 算法思想: 1〉从第一个元素开始,该元素可以认为已经被排序 2〉取出第一个未排序元素存放在临时变量temp中,在已经排序的元素序列中从后往前扫描,逐一比较 3〉如果temp小于已排序元素,将该元素移到下个位置 4〉重复步骤3〉,直到找到已排序的元素小于或者等于 public class InsertSort { public static void main(String[] args) { int a[] ={345,54,66,3,76,345,7,4,3} ; a = insertSort(a); String s = Arrays.toString(a); System.out.println(s); } public static int[] insertSort(int[] ary){ for(int i = 1;i < ary.length;i++){ int temp = ary[i]; int j; for(j = i-1;j>=0 && temp < ary[j];j--){ ary[j+1] = ary[j]; } ary[j+1] = temp; } return ary; } } 思路:冒泡+二分+递归分治 对于给定的一组记录,选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分,直到序列中的所有记录均有序为止。 java代码: public class QuickSort{ public static void sort(int a[], int low , int height){ int i , j, index; if(low > height){ return; } i = low; j = height; index = a[i]; //记录下基准数 while( i < j){ while(i < j && a[j] >= index) j--; if(i < j) a[i++] = a[j]; while(i < j && a[i] <= index) i++; if(i < j) a[j--] = a[i] } a[i] = index; sort(a, low, i-1); sort(a, i+1, height); } public static void main(String[] args){ int[] a = {23,5,65,3,7,23,76,24,674,74567,2}; sort(a,0,a.length-1); System.out.print(Arrays.toString(a)); } } 堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。 思想:简单选择排序的升级版,思想就是将每一次的选择排序的结构记录下来。第一步先将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次最大值。如此反复执行,就能得到一个有序序列了。 问题1:如何由一个无序序列建成一个堆?可以直接使用线性数组来表示一个堆,由初始的无序序列建成一个堆就需要自底向上从第一个非叶元素开始挨个调整成一个堆。 问题2:在输出堆顶元素之后,如何将剩余元素成为一个新的堆?首先是将堆顶元素和最后一个元素交换。然后比较当前堆顶元素的左右孩子节点,因为除了当前的堆顶元素,左右孩子堆均满足条件,这时需要选择当前堆顶元素与左右孩子节点的较大者(大顶堆)交换,直至叶子节点。我们称这个自堆顶自叶子的调整成为筛选。 java 代码: public class HeapSort{ /** 堆排序 */ private static void heapSort(int[] arr) { // 将待排序的序列构建成一个大顶堆 for (int i = arr.length / 2; i >= 0; i--){ heapAdjust(arr, i, arr.length); } // 逐步将每个最大值的根节点与末尾元素交换,并且再调整二叉树,使其成为大顶堆 for (int i = arr.length - 1; i > 0; i--) { swap(arr, 0, i); // 将堆顶记录和当前未经排序子序列的最后一个记录交换 heapAdjust(arr, 0, i); // 交换之后,需要重新检查堆是否符合大顶堆,不符合则要调整 } } /** 构建堆的过程, arr 需要排序的数组, i 需要构建堆的根节点的序号,n 数组的长度*/ private static void heapAdjust(int[] arr, int i, int n) { int child; int father; for (father = arr[i]; leftChild(i) < n; i = child) { child = leftChild(i); // 如果左子树小于右子树,则需要比较右子树和父节点 if (child != n - 1 && arr[child] < arr[child + 1]) { child++; // 序号增1,指向右子树 } // 如果父节点小于孩子结点,则需要交换 if (father < arr[child]) { arr[i] = arr[child]; } else { break; // 大顶堆结构未被破坏,不需要调整 } } arr[i] = father; } // 获取到左孩子结点 private static int leftChild(int i) { return 2 * i + 1; } // 交换元素位置 private static void swap(int[] arr, int index1, int index2) { int tmp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = tmp; } } public void insertMinHeap(int arr[], int i){ int parent = (i-1) / 2; while(parent >= 0&& arr[i] < arr[parent]){ //如果父亲节点的下标大于0,并且当前节点小于父节点交换位置。继续向上比较,否则停止比较 if( i == 0) break; int temp = arr[parent]; arr[parent] = arr[i]; arr[i] = temp; i = parent; parent = (i - 1) / 2; } } java api 中关于插入堆的操作(小顶堆) private void siftUp(int t, int arr[] ){ int key = arr[k]; while (k > 0){ int parent = ( k -1) >>>1; int e = arr[parent]; if(arr[parent] < arr[k]) break; k = parent; } arr[k] = key; } 希尔排序是插入排序的一种高效率的实现,也叫缩小增量排序。简单的插入排序中,如果待排序列是正序时,时间复杂度是O(n),如果序列是基本有序的,使用直接插入排序效率就非常高。希尔排序就利用了这个特点。基本思想是:(1)先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时再对全体记录进行一次直接插入排序。(2)增量初值通常为数据序列长度的一半,以后每趟增量减半,最后值为1。随着增量逐渐减小,组数也减小,组内元素个数增加,数据序列接近有序。 java 实现: (1)最外层循环for语句以增量d变化控制进行若干趟扫描,d的初值为序列长度的一半,以后每趟减半,直至为1; (2)中间for循环进行一趟扫描,序列分为d组,每组由相距为d远的n/d个元素组成,每组元素分别进行直接插入排序; (3)最内层循环for语句进行一组直接插入排序,将一个a[i]插入到其所在组前面的排序子序列中。 public void shellsort(int[] a){ for(int d=a.length/2;d>0;d=d/2) { System.out.println("d="+d);选择排序:
插入排序:
快速排序:(时间复杂度nlogn, 空间复杂度nlogn)
堆排序:(时间复杂度O(nlgn))
注:例外一种建堆的方式:(一个一个插入堆,小顶堆)
希尔排序