注意:快排的空间复杂度是O(logn),归并的额外空间复杂度是O(n),上面写错了。
选择排序:从n个数中选出最小的,放在最前面,再从n-1选出最小的放在第二个。。。
快排:最好的情况是枢纽元选取得当,每次都能均匀的划分序列。 时间复杂度O(nlogn)
最坏情况是枢纽元为最大或者最小数字,那么所有数都划分到一个序列去了时间复杂度为O(n^2)。空间复杂度是递归
swap交换两个数,如果使用异或,不能自己跟自己交换,因为自己异或自己得0,需要提前判断。
插入排序的时间复杂度分析。在最坏情况下,数组完全逆序,插入第2个元素时要考察前1个元素,插入第3个元素时,要考虑前2个元素,……,插入第N个元素,要考虑前 N - 1 个元素。因此,最坏情况下的比较次数是 1 + 2 + 3 + … + (N - 1),等差数列求和,结果为 N^2 / 2,所以最坏情况下的复杂度为 O(N^2)。
最好情况下,数组已经是有序的,每插入一个元素,只需要考查前一个元素,因此最好情况下,插入排序的时间复杂度为O(N)。
冒泡排序最好情况,数组已经有序,虽然还是两层循环,但内层循环每次只用比较一次,不需要交换(A[j]<A[j+1])。
希尔排序:插入排序的改良版,往前插入的步长不是1,比如是3(步长选择越优,时间复杂度越低,步长选择越差,越趋近于O(n2),进行完步长为3的调整后,再进行步长为2的,再进行步长为1的,希尔排序最终都会以步长为1的结束)。步长一开始是feet=length/2,然后循环一次feet=feet/2
shell排序的平均复杂度是O(nlogn)~O(n2),最好的情况O(n1.3),最坏的情况O(n2)
基数排序:把n个数,按个位放入0-9个桶,再按顺序取出,再按十位。。百位
该算法所花的时间基本是在把元素分配到桶里和把元素从桶里串起来;把元素分配到桶里:循环 length 次;
把元素从桶里串起来:这个计算有点麻烦,看似两个循环,其实第二循环是根据桶里面的元素而定的,可以表示为:k×buckerCount;其中 k 表示某个桶中的元素个数,buckerCount 则表示存放元素的桶个数;
有几种特殊情况:
第一、所有的元素都存放在一个桶内:k = length,buckerCount = 1;
第二、所有的元素平均分配到每个桶中:k = length/ bukerCount,buckerCount = 10;(这里已经固定了10个桶(0-9))
所以平均情况下收集部分所花的时间为:length (k×buckerCount)(也就是元素长度 n)
综上所述:时间复杂度为:posCount * (length + length) ;其中 posCount 为数组中最大元素的最高位数(位数);简化下得:O( k*n ) ;其中k为常数,n为元素个数;
计数排序:排列员工身高,时间复杂度O(n+k),k为桶的个数(一个桶的一次性倒出)
堆排序:
堆排序是一种选择排序,其时间复杂度为O(nlogn)。堆是一个完全二叉树,父节点均大于等于或小于等于其两个子节点(只有堆顶元素是最大或最小,其他无序),一般采用数组存储堆,如果下表从0开始,i的子节点为2i+1和2i+2,i的父节点(i-1)/2.
堆排序的步骤:
一般在输出堆顶元素之后,视为将这个元素排除,然后用表中最后一个元素填补它的位置,自上向下进行调整:首先将堆顶元素和它的左右子树的根结点进行比较,把最小的元素交换到堆顶;然后顺着被破坏的路径一路调整下去,直至叶子结点,就得到新的堆。我们称这个自堆顶至叶子的调整过程为“筛选”。
从无序序列建立堆的过程就是一个反复“筛选”的过程。
1、构造初始堆(O(n))
初始化堆的时候是对所有的非叶子结点进行筛选。
最后一个非叶子节点的下标是(n/2-1),所以筛选只需要从第(n/2-1)个元素开始,从后往前进行调整。
然后从最后一个非叶子结点开始,每次都是从父结点、左孩子、右孩子中进行比较交换,交换可能会引起孩子结点不满足堆的性质,所以每次交换之后需要重新对被交换的孩子结点进行调整。
2、进行堆排序(O(nlogn))
有了初始堆之后就可以进行排序了。
堆排序是一种选择排序。建立的初始堆为初始的无序区。
排序开始,首先输出堆顶元素(因为它是最值),将堆顶元素和最后一个元素交换,这样,第n个位置(即最后一个位置)作为有序区,前n-1个位置仍是无序区,对无序区(筛选前n-1个位置)进行调整(此时只有堆顶元素不满足堆的要求),得到堆之后,再交换堆顶和最后一个元素,这样有序区长度变为2。
不断进行此操作,将剩下的元素重新调整为堆,然后输出堆顶元素到有序区。每次交换都导致无序区-1,有序区+1。不断重复此过程直到有序区长度增长为n-1,排序完成。(需要用大根堆实现,因为每次堆顶元素(最大值)交换到最后)
堆的插入与删除
堆是完全二叉树,插入时在最后一个位置添加节点,然后自底向上调整堆。
删除时,只能删除根节点,将堆的最后一个节点放到根节点,然后自顶向下调整堆。
public static void printNums(int[] nums){
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
}
public void bubbleSort(int[] nums){
for (int i = nums.length-1; i >=0;i--) {
for (int j = 0; j < i; j++) {
if (nums[j]>nums[j+1]){
swap(nums,j,j+1);
}
}
}
}
public void insertionSort(int[] nums){
for (int i = 1; i < nums.length; i++) {
for (int j = i-1; j >=0 ; j--) {
if (nums[j+1]<nums[j]){
swap(nums,j+1,j);
}
}
}
}
public void heapSort(int[] nums){
if (nums.length<2){
return;
}
for (int i = 0; i < nums.length; i++) {
heapInsert(nums,i);
}
int size =nums.length;
swap(nums,0,--size);
while (size>0) {
heapify(nums,0,size);
swap(nums,0,--size);
}
}
public void heapInsert(int[] nums,int index){
while (nums[index]>nums[(index-1)/2]){
swap(nums,index,(index-1)/2);
index = (index-1)/2;
}
}
public void heapify(int[] nums, int index, int size){
int left = index*2+1;
while (left<size) {
int largest = left+1<size&&nums[left+1]>nums[left]?left+1:left;
if (nums[index]>=nums[largest]){
break;
}
swap(nums,index,largest);
index = largest;
left = index * 2 + 1;
}
}
public void selectionSort(int[] nums){
for (int i = 0; i < nums.length; i++) {
int minIndex = i;
for (int j = i+1; j < nums.length; j++) {
if (nums[j]<nums[minIndex]){
minIndex = j;
}
}
swap(nums,i,minIndex);
}
}
public void quickSort(int[] nums){
if (nums.length<2){
return;
}
quickSort(nums,0,nums.length-1);
}
public void quickSort(int[] nums,int left,int right){
if (left<right){
int[] help = partition(nums, left, right);
quickSort(nums,left,help[0]-1);
quickSort(nums,help[1]+1,right);
}
}
public int[] partition(int[] nums,int left,int right){
int less = left - 1;
int more = right;
while (left<more){
if (nums[left]<nums[right]){
swap(nums,++less,left++);
}
else if (nums[left]>nums[right]){
swap(nums,--more,left);
}else {
left++;
}
}
swap(nums,more,right);
return new int[]{less+1,more};
}
public void mergeSort(int[] nums){
if (nums.length<2){
return;
}
mergeSort(nums,0,nums.length-1);
}
public void mergeSort(int[] nums, int left, int right){
if (left==right){
return;
}
int mid = (left+right)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
public void merge(int[] nums,int left, int mid ,int right){
int[] help = new int[right-left+1];
int l = left;
int r = mid +1;
int index = 0;
while (l<=mid&&r<=right){
if (nums[l]<nums[r]){
help[index++] = nums[l++];
}else {
help[index++] = nums[r++];
}
}
while (l<=mid){
help[index++] = nums[l++];
}
while (r<=right){
help[index++] = nums[r++];
}
for (int i = 0; i < help.length; i++) {
nums[left++] = help[i];
}
}
public void swap(int[] nums , int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void bucketSort(int[] nums){
int max = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
max = Math.max(max,nums[i]);
}
int[] bucket = new int[max+1];
for (int i = 0; i < nums.length; i++) {
bucket[nums[i]]++;
}
int index = 0;
for (int i = 0; i < bucket.length; i++) {
while (bucket[i]>0){
bucket[i]--;
nums[index++] = i;
}
}
}