数据结构与算法-插入排序

953 阅读2分钟

1,插入排序

插入排序就是在已经有序的序列中,插入元素,使得插入后的整个序列依然是有序的。

1.1 ,插入排序的实现

执行流程

  1. 在执行过程中,插入排序会讲序分为两部分:头部是已经排好的序列,尾部是带排序的序列
  2. 从头开始扫描每一位元素:每当扫描到一个元素,就将它插入到头部合适的位置,使得头部数据依然保持有序

代码实现

for (int begain = 1; begain < array.length; begain++) {
    //保存扫面元素的位置
    int cur = begain;
    //当cur==0时,进行下一个扫描
    while (cur > 0 && cmp(cur, cur - 1) < 0) {
        //交换两个元素
        swap(cur, cur - 1);
        cur --;
    }
}

1.2,插入排序-优化

思路:将 交换 改为 挪动

  1. 先将待插入的元素备份
  2. 头部有序数据中比待插入的元素大,都朝尾部方向挪动1个位置
  3. 将待插入元素放到最终的合适位置

代码实现

for (int begain = 1; begain < array.length; begain++) {
    //记录遍历位置
    int cur = begain;
    //备份插入的元素
    T v = array[cur];
    //当cur==0时,进入下一个扫描
    while (cur > 0 && cmp(v,array[cur - 1]) < 0) {
        //元素向后挪动
        array[cur] = array[cur - 1];
        cur --;
    }
    //在cur位置插入元素
    array[cur] = v;
}

2,二分搜索

  1. 如果是无序数组,需要从第0个位置开始遍历搜索。平均时间复杂度为:O(n)
  2. 如果是有序数组,可以使用二分搜索,最坏时间复杂度:O(logn)

思路

  1. 假设在[begain,end)范围内搜索某个元素V,mid == (begain + end) / 2
  2. 如果v < m, 去[begain, mid)范围内二分搜索
  3. 如果v > m, 去[mid + 1, end)范围内二分搜索
  4.  如果v == m,直接返回mid

搜索实例

搜索10:

  1. mid = (0 + 7)/ 2 = 3,取出8和10比较,8小于10所以取右边
  2. 然后算出右边的mid = (3+7)/ 2 = 5。12比10大,继续二分查找
  3. 最后在4的位置命中

同理搜索3,最后begain == end == 1,没有找到,失败。

代码实现

public static int search(int[] array,int v) {
    //如果array不存在,就return
    if (array == null || array.length == 0) return -1;
    //设置起始位置
    int begain = 0;
    //设置末尾位置
    int end = array.length;
    //进行遍历
    while (begain < end) {
        //取出中间位置
        int mid = (begain + end) >> 1;
        if (v < array[mid]) {
            //中间位置索引变为end
            end = mid
        } else if (v > array[mid]) {
            //中间位置加1的索引,变为begain
            begain = mid + 1;
        } else {
            //没有找到就返回,最后的中间索引
            return mid;
        }
    }
    reutrn -1;
}

3,插入排序-二分搜索优化

  • 在元素 v 的插入过程中,可以先二分搜索出合适的插入位置,然后再将元素 v 插入
  • 要求二分搜索返回的插入位置:第一个大于v的元素位置

例如:

如果 v 是 5,返回索引 2

如果 v 是 1,返回索引 0

如果 v 是 15,返回索引 7

如果 v 是8,返回索引 5

思路

  • 假设在[begain, end)范围内搜索某个元素 v ,mid == (begain + end)/ 2
  • 如果 v < m , 去[begian,mid)范围内二分搜索
  • 如果 v >= m, 去[mid + 1,end)范围内二分搜索

实现

//插入方法实现,seource:遍历的当前索引位置。dest:要插入的索引的位置
private void insert(int source, int dest) {
    //备份当前元素
    T v = array[source];
    //source的索引位置大于dest的位置,进行挪动
    for (int i = source; i > dest; i-- ) {
        array[i] = array[i - 1];
    }
    array[dest] = v;
}
//二分搜索,找到插入位置对应的索引
private int search(int index) {
    int begain = 0;
    int end = index;
    while (begain < end) {
        int mid = (begian + end) >> 1;
        if (cmp(index, mid) < 0) {
            end = mid;
        } else {
            begain = mid + 1;
        }
    }
    return begain;
}

//调用实现
for (int i = 1; i < array.length; i++) {
    insert(i, search(i));
}