算法导论第二章

1. 递归版插入排序

主要思路: 可以把插入排序表示为如下一个递归过程:为了排序A[1..n],我们递归地排序A[1..n-1], 然后把A[n]插入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[N];
        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];
         }
    }
}

转载于:https://my.oschina.net/yitiaoxianyu/blog/1571691

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值