zoukankan      html  css  js  c++  java
  • 十归并排序有用的算法和二进制搜索的基础

    归并排序

    归并排序是建立在归并操作上的一种有效的排序算法。该算法是採用分治法(Divide and Conquer)的一个很典型的应用。

    算法步骤:

    1. 申请空间,使其大小为两个已经排序序列之和。该空间用来存放合并后的序列

    2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置

    3. 比較两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

    4. 反复步骤3直到某一指针达到序列尾

    5. 将还有一序列剩下的全部元素直接拷贝到合并序列尾

    程序猿必须知道的10大基础有用算法及其解说 - 第3张  | 快课网

    用分治策略解决这个问题分为三步:分解、解决、合并

    也即:将原问题划分成n个规模较小而结构与原问题相似的子问题; 递归地解决这些子问题。然后再合并其结果,得到原问题的解。此处n=2。每次都把原问题划分为两个子问题。


    归并排序的伪代码(来自算法导论)

    合并排序伪代码(使用哨兵):
    merge(A,p,q,r)://合并算法,[p,q],[q+1,r]
        n1 <—— q-p+1
        n2 <—— r-q
        create array L[0,n1] and R[0,n2]
        for i <—— 0 to n1-1
            do L[i] <—— A[p+i]
        for j <—— 0 to n2-1
            do R[j] <—— A[q+j+1]
        L[n1] <—— +∞
        R[n2] <—— +∞
        i <—— 0
        j <—— 0
        for k i <—— p to r
            do if L[i]<=R[j]
                then A[k]  <—— L[i]
                     i <—— i+1
               else A[k] <—— R[j]
                     j <—— j+1
     
    //通过调用merge完毕排序:
    merge_sort(A,p,r):
        if p<r
           then q <—— [(p+r)/2] //向下取整
              merge_sort(A,p,q) //分治
              merge_sort(A,q+1,r)
              merge(A,p,q,r)    //合并结果

     归并排序实现

    #include <stdio.h>
    #include <stdlib.h>
    #define MAX_INT  ~(1<<31)//最大整数
    //arr[p,q]  arr[q+1,r]
    void merge(int *arr,int p,int q,int r)
    {
        if(arr==NULL)
            return;
        int n1=q-p+1;
        int n2=r-q;
        int *L=(int*)malloc((n1+1)*sizeof(int));//申请新空间用于暂时存储元素
        int *R=(int*)malloc((n2+1)*sizeof(int));
        int i,j;//这里直接申请一个r-p+1长度的数组,在暂时数组中排序后拷贝回原数组
        for(i=0;i<n1;++i)
            L[i]=arr[p+i];
        for(j=0;j<n2;++j)
            R[j]=arr[q+j+1];
        //哨兵元素赋值
        L[n1]=MAX_INT;
        R[n2]=MAX_INT;
        int k;
        i=0,j=0;
        for(k=p;k<=r;++k){
            if(L[i]<=R[j])
                arr[k]=L[i++];
            else
                arr[k]=R[j++];
        }//最后可能有一个数组有元素剩余,这里使用一个哨兵(MAX_INT)能够在一次循环中完毕所有复制
        free(L);
        free(R);
    }
    void merge_sort(int *arr,int p,int r)
    {
        if(p<r){
            int q=(r+p)/2;
            merge_sort(arr,p,q);//分治
            merge_sort(arr,q+1,r);
            merge(arr,p,q,r);//合并结果
        }
     
    }
     int main()
    {
        int arr[8]={32,3,4,5,6,7,9,106};
        merge_sort(arr,0,7);
        for (int i=0;i<8;i++)
        printf("%d ",arr[i]);
        system("pause");
    }

    二分查找算法

    二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素開始,假设中间元素正好是要查找的元素。则搜素过程结束;假设某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,并且跟開始一样从中间元素開始比較。假设在某一步骤数组为空,则代表找不到。

    这样的搜索算法每一次比較都使搜索范围缩小一半。

    折半搜索每次把搜索区域降低一半,时间复杂度为Ο(logn) 。


    二分查找能够解决(预排序数组的查找)问题:仅仅要数组中包括T(即要查找的值),那么通过不断缩小包括T的范围,终于就能够找到它。其算法流程例如以下:

    • 1、一開始,范围覆盖整个数组。

    • 2、将数组的中间项与T进行比較,假设T比数组的中间项要小,则到数组的前半部分继续查找,反之,则到数组的后半部分继续查找。
    • 3、如此,每次查找能够排除一半元素。范围缩小一半。就这样重复比較,重复缩小范围,终于就会在数组中找到T,或者确定原以为T所在的范围实际为空。

    对于包括N个元素的表,整个查找过程大约要经过log(2)N次比較。

    //首先要把握以下几个要点:
    //right = n-1 => while(left <= right) => right = middle-1;
    //right = n   => while(left <  right) => right = middle;
    //middle的计算不能写在while循环外,否则无法得到更新。

    int BinarySearch(int array[], int n, int value) { int left = 0; int right = n - 1; //假设这里是int right = n 的话,那么以下有两处地方须要改动,以保证一一相应: //1、以下循环的条件则是while(left < right) //2、循环内当 array[middle] > value 的时候,right = mid while (left <= right) //循环条件,适时而变 { int middle = left + ((right - left) >> 1); /*防止溢出。移位也更高效。

    同一时候。每次循环都须要更新。mid = left + (right-left)/2这样写能够有效避免right + left 溢出。假设写成mid = (left + right)/2可能存在溢出*/ if (array[middle] > value) { right = middle - 1; //right赋值,适时而变 } else if(array[middle] < value) { left = middle + 1; } else return middle; //可能会有读者觉得刚開始时就要推断相等。但毕竟数组中不相等的情况很多其它 //假设每次循环都推断一下是否相等,将耗费时间 } return -1; }


    以上就是本次介绍的归并排序和二分查找。



    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    剑指 Offer 51. 数组中的逆序对
    剑指 Offer 68
    剑指 Offer 68
    JS绑定事件三种方式
    图片懒加载原理及实现
    资源加载过程
    了解JS单线程和任务队列!
    JS函数作用域提升
    JS函数种类详解
    ES6之模版字符串
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4806523.html
Copyright © 2011-2022 走看看