6.归并排序
基本思想:
将一个数组分为两块,两块再分两块……最终只需保证两块内数据有序即可
- 代码如下:
public static void mergeSort(int[] arr) {
for (int i = 1; i < arr.length; i *= 2) {
merge(arr,i);
}
}
public static void merge(int[] arr, int gap) {
int left1 = 0;//第一个归并段的起始位置
int right1 = left1 + gap - 1;//第一个归并段的终止位置
int left2 = right1 + 1;//第二个归并段的起始位置
int right2 = left2 + gap - 1 < arr.length ? left2 + gap - 1 : arr.length - 1;//第二个归并段的终止位置
int[] brr = new int[arr.length];
int i = 0;//遍历brr下标
//有两个归并段 <第二个归并段至少有一个数据>
while (left2 < arr.length) {
while (left1 <= right2 && left2<=right2) {
if(arr[left1] < arr[left2]) {
brr[i++] = arr[left1++];
}else{
brr[i++]=arr[left2++];
}
}
if(left1>right1){
for(int j=left2;j<=right2;) {
brr[i++] = arr[j++];
}
}
if(left2>right2){
for(int j=left1;j<=right1;) {
brr[i++] = arr[j++];
}
}
left1=right2+1;
right1=left1+gap-1;
left2=right1+1;
right2=left2 + gap - 1 < arr.length ? left2 + gap - 1 : arr.length - 1;
}
//只有一个归并段
for (int j = left1; j < arr.length; ) {
brr[i++] = arr[j++];
}
for(int j=0;j<arr.length;j++){
arr[j]=brr[j];
}
}
7.堆排序
知识点补充
一、堆排序是对简单选择排序算法的一种改进;二、堆是具有以下性质的完全二叉树
1.大顶堆(大根堆):每个节点的值都大于或等于其左右孩子节点的值
2.小顶堆(小根堆):每个节点的值都小于或等于其左右孩子节点的值
基本思想:
1.从倒数第一个非叶子节点开始,将待排序序列调整为大根堆形式
注意: 调整需要保证 该节点的所有分支节点
全部为大根堆形式
调整倒数第三个非叶子节点时就需要考虑该节点所有分支节点均为大根堆形式
2.调整后整个序列的最大值就是堆顶的根节点。将 其与堆数组的末尾元素交换,此时末尾元素就是最大值,然后 将剩余的n-1个数据重新构造成一个堆,得到n个元素中的次小值,如此反复执行,得到一个有序序列。
- 代码如下:
public static void heapSort(int[] arr) {
for (int i = arr.length/ 2-1; i >= 0; i--) {
//将堆调整为大根堆形式
adjust(arr, i, arr.length);
}
//交换0号下标与“相对最后”数据
for(int j=arr.length-1;j>0;j--){
int temp = arr[0];
arr[0] = arr[j];
arr[j] = temp;
adjust(arr, 0, j);
}
}
public static void heapAdjust(int[] arr,int begin,int end){
//挑选左右孩子最大值
int temp = arr[begin];
for (int i = 2 * begin + 1; i < end; i = 2 * i + 1) {
if (i + 1 < end && arr[i] < arr[i + 1]) {//i保存左右孩子较大值
i++;
}
//较大值与begin位置元素比较->交换
if (arr[i] <= temp)
break;
arr[begin] = arr[i];
begin = i;
}
arr[begin] = temp;
}
总结一下上述堆排序代码:
从代码中可以看出,整个堆排序过程分为 两个for循环
第一个循环:将现在的待排序序列调整为一个大顶堆;
第二个循环:逐步将每个最大的根节点与末尾元素交换,并且再调整为大顶堆。