扫到一眼牛客的算法补习班,讲到校招必会的三种排序算法?据说会这三种不一定能找到工作,但是不会这三个一定找不到工作(快 归并 堆)。
算是作为复习,手敲三种排序:
1.快速排序
比较有用的partition函数,能够取出最小的k个元素。
partition函数里slow指针指向的是第一个大于游标的元素。交换游标跟slow指向的元素返回slow即为游标的位置。
因为是切分树结构,所以时间复杂度O(nlgn)。快速排序是非稳定的。
import java.util.Random;
public class quickSort {
public void Sort(int [] array, int start, int end){
if(start >= end) return;
int mid = partition(array, start, end);
Sort(array, start, mid - 1);
Sort(array, mid + 1, end);
}
public static int partition(int [] array, int start, int end){
Random random = new Random();
//生成[start, end]之间的随机数
int index = random.nextInt(end)%(end - start + 1) + start;
swap(array, index, end);
int quick = start, slow = start;
while(quick < end){
if(array[quick] <= array[end]){
if(quick != slow){
swap(array, quick, slow);
}
quick++;
slow++;
}else{
quick++;
}
}
swap(array, slow, end);
return slow;
}
public static void swap(int [] array, int indexa, int indexb){
int temp = array[indexa];
array[indexa] = array[indexb];
array[indexb] = temp;
}
}
2.归并排序
这里写出二路归并排序,两两分组比较,思想应用场景见《剑指Offer》——数组中的逆序对。
归并排序是稳定排序,且也是树形切分,复杂度O(nlgn)。
public class mergeSort {
public void Sort(int [] array, int start, int end){
int startA = start, endA = (start + end)/2;
int startB = endA + 1, endB = end;
if(end <= start)
return;
Sort(array, startA, endA);
Sort(array, startB, endB);
Merge(array, startA, endA, startB, endB);
}
public static void Merge(int [] array, int sa, int ea, int sb, int eb){
int i = sa, k = sb, index = 0;
int [] temp = new int [array.length];
while(i <= ea && k <= eb){
if(array[i] < array[k]){
temp[index++] = array[i++];
}else{
temp[index++] = array[k++];
}
}
while(i <= ea)
temp[index++] = array[i++];
while(k <= eb)
temp[index++] = array[k++];
for(int t = 0, r = sa; t < index; ++t, ++r){
array[r] = temp[t];
}
}
}
3.堆排序
挺有意思的一种排序,分两个步骤
1)先建立最大堆,从倒数第一个有孩子的节点开始往上调整;
2)每次把堆顶放在已经排序的数组的第一位。
public class heapSort {
public static void Sort(int [] array){
buildMaxHeap(array, array.length - 1);
System.out.println(Arrays.toString(array));
for(int i = array.length - 1; i >= 1; --i){
int tempnum = array[0];
array[0] = array[i];
array[i] = tempnum;
maxHeapAdj(array, 0, i);
}
}
public static void maxHeapAdj(int [] array, int from, int tol){
//调整的节点为from节点,每次跟自己的左右孩子的最大的比较,然后下移
//节点的左右孩子的下标分别为2i+1,2i+2
int temp = array[from];
int k = 2*from + 1;
while(k < tol){
if(k + 1 < tol && array[k] < array[k + 1])
k++;
//左右孩子里较大的那个都比待调整节点小,则现在的位置就是待调整的位置
if(array[k] < temp)
break;
array[from] = array[k];
from = k;
k = 2*from + 1;
}
array[from] = temp;
}
//建立最大堆的过程,所有的叶子节点认为是已经合理的堆,调整节点是从第一个有孩子的节点开始调整。
public static void buildMaxHeap(int [] array, int tol){
for(int i = tol/2 + 1; i >=0; --i){
maxHeapAdj(array, i, tol);
}
}
}