您的位置:首页 > 其它

算法导论第二章

2017-11-11 00:00 162 查看

1. 递归版插入排序

主要思路: 可以把插入排序表示为如下一个递归过程:为了排序A[1..n],我们递归地排序A[1..n-1], 然后把A
插入A[1..n-1]

    有了思路,写代码就比较容易了,如下

public static void insertSortRecursive(int[] arr) {
insertSortRecursiveHelper(arr, arr.length - 1);
}
public static void insertSortRecursiveHelper(int[] arr, int len) {
if (len >= 1) { // 排序A[0..n - 1]时,递归排序A[0..n-2]
insertSortRecursive0(arr, len - 1);
}
// 然后把A[n-1] 插入A[0..n-2]
int t = arr[len];
int i = len - 1;
for (;i >= 0 && t < arr[i]; i--) {
arr[i + 1] = arr[i];
}
arr[i + 1] = t;
}

2. 递归版二分查找

    由于二分查找在每次查找时都是在原来的一半范围内查找指定的数,因此很容易写成递归形式

public static int binarySearchRecursive(int[] arr, int target) {
return binarySearchRecursiveHelper(arr, target, 0, arr.length - 1);
}
public static int binarySearchRecursiveHelper(int[] arr, int target, int start, int end) {
if(start <= end) {
int mid = start + ((end - start) >> 1);
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return binarySearchRecursiveHelper(arr, target, start, mid - 1);
} else {
return binarySearchRecursiveHelper(arr, target, mid + 1, end);
}
}
return -1;
}

3. 利用二分查找加速插入排序

    由于插入排序需要在数组已经排有序的元素中寻找一个位置,来插入新的数据。因此,寻找位置的过程是在有序数组中进行,可以二分来加速查找插入位置这一过程。

public static void advanceInsertSortWithBinarySearch(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int temp = arr[i];
int low = 0, high = i - 1;
int mid = -1;
while (low <= high) {
mid = low + ((high - low) >> 1);
if (arr[mid] > temp) {
high = mid - 1;
} else { // 元素相同时,也插入在后面的位置
low = mid + 1;
}
}

for(int j = i - 1; j >= low; j--) {
arr[j + 1] = arr[j];
}
arr[low] = temp;
}
}

4. 用归并排序统计数组中逆序对的数目

题目:给一列数a1,a2,...,an,求它的逆序对数,即有多少个有序对(i,j),使得i<j且ai>aj。也就是求逆序对的数目。

分析:在归并排序的合并过程中,对于有序数组arr[low..mid], 和有序数组arr[mid+1..high], 有low<=i<=mid,mid+1<=j<=high。如果arr[i]>arr[j], 则arr[i..mid]中的所有数都要大于arr[j], 从而可以得到mid-i+1个逆序对。将所有合并过程中的逆序对相加即可得到整个初始数组的逆序对。

    代码如下所示:

public class Main {
public static final int N = 10;
public static int result = 0;

public static void main(String[] args) {
int[] arr = new int
;
for (int i = 0; i < N; i++) {
arr[i] = (int) (Math.random() * 100);
System.out.print(arr[i] + " ");
}
reversePair(arr);
System.out.println("\n逆序对数:" + result);
}

public static void reversePair(int[] arr) {
mergeSort(arr, 0, arr.length - 1);
}

public static void mergeSort(int[] arr, int low, int high) {
if (low < high) {
int mid = low + ((high-low) >> 1);
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}

public static void merge(int[] arr, int low, int mid, int high) {
int[] arr1 = new int[mid - low + 1];
int[] arr2 = new int[high - mid];
int i, j;
for (i = 0; i < arr1.length; i++) {
arr1[i] = arr[low + i];
}
for (j = 0; j < arr2.length; j++) {
arr2[j] = arr[mid + 1 + j];
}
i = j = 0;
int index = low;
while (i < arr1.length && j < arr2.length) {
if (arr1[i] > arr2[j]) {
arr[index++] = arr2[j++];
result += mid - low - i + 1;  // 此处的mid-low-i才是上面分析中mid-i的值
} else {
arr[index++] = arr1[i++];
}
}
while (i < arr1.length) {
arr[index++] = arr1[i++];
}
while (j < arr2.length) {
arr[index++] = arr2[j++];
}
}
}

    当然,也可以将mergeSort方法改为如下:

public static void mergeSort(int[] arr, int low, int high) {
if (low < high) {
int mid = low + ((high - low) >> 1);
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);

int[] temp = new int[high - low + 1];
int i = low, j = mid + 1;
int index = 0;
while (i <= mid && j <= high) {
if (arr[i] > arr[j]) {
temp[index++] = arr[j++];
result += mid - i + 1;
} else {
temp[index++] = arr[i++];
}
}
while (i <= mid) {
temp[index++] = arr[i++];
}
while (j <= high) {
temp[index++] = arr[j++];
}
for (i = low; i <= high; i++) {
arr[i] = temp[i - low];
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  排序 算法导论