归并排序
归并排序采用经典的分治策略。将一个数组一直对半分,问题的规模就减小了,再重复进行这个过程,直到元素的个数为一个时,一个元素就相当于是排好顺序的;接下来就是合并,将两个元素,四个元素按顺序合并。
实现代码如下所示:
public static void mergeSort(int[] array) {
// 在排序前建好临时数组,避免递归中频繁开辟空间
int[] temp = new int[array.length];
mergeSort(array, 0, array.length - 1, temp);
}
public static void mergeSort(int[] array, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
// 左边递归排序,使得左子序列有序
mergeSort(array, left, mid, temp);
// 右边递归排序,使得右子序列有序
mergeSort(array, mid + 1, right, temp);
// 将两个有序数组合并
merge(array, left, mid, right, temp);
}
}
public static void merge(int[] array, int left, int mid, int right, int[] temp) {
// 左序列指针
int i = left;
// 右序列指针
int j = mid + 1;
// 临时数组指针
int t = 0;
while (i <= mid && j <= right) {
if (array[i] < array[j])
temp[t++] = array[i++];
else
temp[t++] = array[j++];
}
// 将左序列剩余元素放进temp中
while (i <= mid) {
temp[t++] = array[i++];
}
// 将右序列剩余元素放进temp中
while (j <= right) {
temp[t++] = array[j++];
}
t = 0;
// 将排序好的数组复制进原数组
while (left <= right) {
array[left++] = temp[t++];
}
}
public static void main(String[] args) {
int[] array = {10, 7, 2, 4, 7, 62, 3, 4, 2, 1, 19};
mergeSort(array);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
过程示意图如下所示:
归并排序是稳定排序,平均时间复杂度均为O(nlogn),空间复杂度为O(n)。
堆排序
堆排序是将数据看成是完全二叉树,根据完全二叉树的特性来进行排序的一种算法。
最大堆要求节点的元素都要不小于其子节点。那么处于最大堆的根节点的元素一定是这个堆中的最大值。下图即为一个最大堆,且完全二叉树有一个特性:左子节点下标 = 当前父节点下标 * 2 +1,右子节点下标 = 当前父节点下标 * 2 + 2。
堆排序过程示意图如下所示:
实现过程如下所示:
public static void heapify(int[] arrays, int currentRootNode, int size) {
if (currentRootNode < size) {
//左子树和右字数的位置
int left = 2 * currentRootNode + 1;
int right = 2 * currentRootNode + 2;
//把当前父节点位置看成是最大的
int max = currentRootNode;
if (left < size) {
//如果比当前根元素要大,记录它的位置
if (arrays[max] < arrays[left]) { max = left; }
}
if (right < size) {
//如果比当前根元素要大,记录它的位置
if (arrays[max] < arrays[right]) { max = right; }
}
//如果最大的不是根元素位置,那么就交换
if (max != currentRootNode) {
int temp = arrays[max];
arrays[max] = arrays[currentRootNode];
arrays[currentRootNode] = temp;
//继续比较,直到完成一次建堆
heapify(arrays, max, size);
}
}
}
public static void maxHeapify(int[] arrays, int size) {
// 从数组的尾部开始,直到第一个元素(角标为0)
for (int i = size - 1; i >= 0; i--) {
heapify(arrays, i, size);
}
}
public static void heapSort(int[] array){
for (int i = 0; i < array.length; i++) {
//每次建堆就可以排除一个元素了
maxHeapify(array, array.length - i);
//交换
int temp = array[0];
array[0] = array[(array.length - 1) - i];
array[(array.length - 1) - i] = temp;
}
}
public static void main(String[] args) {
int[] array = {10, 7, 2, 4, 7, 62, 3, 4, 2, 1, 19};
heapSort(array);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
堆排序时间复杂度O(nlogn),空间复杂度O(1)。