zoukankan      html  css  js  c++  java
  • 排序与查找

    一.排序

    1.非线性排序

       a.归并排序

          1)基本思想:将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。

          2)Step1: 把待排序的n个记录看作长度为1的有序序列。将相邻子序列两两归并为长度为2或1的有序序列;

             Step2 :把得到的n/2个长度为2的有序子序列再归并为长度为 2*2 的有序序列;

             Step3 :按Step2的方式,重复对相邻有序子序列进行归并操作,直到成为一个有序序列为止。 

             动画演示:http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?id=93

           3)代码            

     void merge_sort(int data[], int left, int right)
      {
           if(left< right)
           {
              int mid = (left+ right) / 2;
              merge_sort(data, left, mid);
              merge_sort(data, mid+1, right);
              merge(data, left, mid, right);
            }
      }
    
    
    void merge(int array[], int p, int q, int r)
     {     
       int i,k;    int begin1,end1,begin2,end2;
       int* temp = new int [r-p+1]; 
    //申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
    //设定两个指针,最初位置分别为两个已经排序序列的起止位置
       begin1= p;     end1 = q;     
       begin2 = q+1;  end2 = r;  
       k = 0;
         while((begin1 <= end1)&&( begin2 <= end2)) 
        { if(array[begin1]<array[begin2])
             {temp[k] = array[begin1];  begin1++; 
             }
             else
             {temp[k] = array[begin2];  begin2++;
              }
             k++;        
         } 
         //若第一个序列有剩余,拷贝出来粘到合并序列尾 
         while(begin1<=end1) 
             temp[k++] = array[begin1++]; 
           //若第二个序列有剩余,拷贝出来粘到合并序列尾         
    while(begin2<=end2) temp[k++] = array[begin2++];
    for (i = 0; i < (r - p +1); i++) //将排序好的序列拷贝回数组中 array[p+i] = temp[i]; delete[] (temp); }

         4)复杂度

              O(nlogn) 渐进意义下的最优算法

       b.起泡排序

         1)起泡排序基本思想: 设数组a中存放了n个数据元素,循环进行n-1趟如下的排序过程: 依次比较相临两个数据元素,若a[i]>a[i+1],则交换两个数据元               素,否则不交换。 当完成一趟交换以后,最大的元素将会出现在数组的最后一个位置。 依次重复以上过程,当第n-1趟结束时,整个n个数据元素集合中次             小的数据元素将被放置在a[1]中,a[0]中放置了最小的数据元素。

         2)伪代码          

    1 // 将a中整数序列排列成自小至大有序的序列void bubblf_sort(array a[])
    2  {  for(i=1,i<array.length;++i)   //比较趟数
    3      for(j=0;j<array.length-i;++j)
    4         if(a[j]>a[j+1])
    5         a[j] ←→ a[j]; 
    6 }

        c.快速排序

           1)基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据             分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列(动画演示http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?             id=86)

            2)算法过程:指定枢轴(通常为第一个记录) 通过一趟排序将以枢轴为中心,把待排记录分割为独立的两部分,使得左边记录的关键字小于枢轴值,右边记录              的关键字大于枢轴值 对左右两部分记录序列重复上述过程,依次类推,直到子序列中只剩下一个记录或不含记录为止。

            3)算法步骤:

                 step1:分解(Divide):将输入的序列L[p..r]划分成两个非空子序列L[p..q]和L[q+1..r],使L[p..q]中任一元素的值不大于L[q+1..r]中任一元素的值。                step2:递归求解(Conquer):通过递归调用快速排序算法分别对L[p..q]和L[q+1..r]进行排序。

                 step3:合并(Merge):由于对分解出的两个子序列的排序是就地进行的,所以在L[p..q]和L[q+1..r]都排好序后不需要执行任何计算L[p..r]就已排好序。

             4)代码           

     1 void quicksort(int number[], int left, int right) 
     2   { int q; 
     3     if(left < right)
     4     {  q=partition(number, left, right); //分解
     5         quicksort(number, left, q-1); //排序
     6         quicksort(number, q+1, right); 
     7     } 
     8 }
     9 int partition(int number[], int left, int right)
    10  { int s; 
    11     s = number[left]; 
    12    while(left<right)  
    13    { // 从表的两端交替地向中间扫描
    14      while(number[right]>s)      right--;
    15      while(number[left]<s)         left++;
    16     SWAP(number[left], number[right]);  
    17    }
    18    number[left]=s; // 枢轴记录到位
    19    return left; // 返回枢轴位置
    20  }
    21 
    22 #define MAX 10 
    23 #define SWAP(x,y) {int t; t = x; x = y; y = t;} 
    24 void main()
    25  { int number[MAX] = {0};    int i;  
    26     srand(time(NULL)); 
    27     cout<<"排序前:"; 
    28     for(i = 0; i < MAX; i++) 
    29     { number[i] = rand() % 100; 
    30       cout<<setw(6)<<number[i]; 
    31     }     
    32     quicksort(number, 0, MAX-1);     
    33     cout<<"
    排序后:"; 
    34     for(i = 0; i < MAX; i++) 
    35     cout<<setw(6)<<number[i]; 
    36     cout<<"
    "; 
    37 } 
    View Code

             5) 复杂度               

                      对于n个成员,快速排序法的比较次数大约为n*logn 次,交换次数大约为(n*logn)/6次。如果n为100,冒泡法需要进行4950 次比较,而快速排序                 法仅需要200 次。快速排序法的性能与中间值的选定关系密切,如果每一次选择的中间值都是最大值(或最小值),该算法的速度就会大大下降。 快速                 排序算法最坏情况下的时间复杂度为O(n2),而平均时间复杂度为O(n*logn)

    2.线性排序

       a.计数排序

          1)解释:

                   集合A有n个元素,每一个元素的值是介于0到k之间的整数。

                   输入:A[1..n] 存放排序结果:B[1..n] 临时存储: C[0..k](存储数组每个坐标做对应的数值的个数)

                   计数排序的基本思想是对每一个输入元素x,确定出小于x的元素个数。有了这一信息,就可以把x直接放到它在最终输出数组 的位置上。例如:若有5个元素小于x,则x就属于第6个输 出位置 。

          2)代码:           

    Count-Sort(A,B,k) //0<=a[i]<=k
    for i←0 to k
    do  C[i] ←0                                                   
    for j← 1 to length[A]
    do    C[A[j]]← C[A[j]] +1
    for i← 1 to  k
    do    C[i]← C[i] +C[i-1]
    for j←length[A] downto 1
    do    B[C[A[j]]] ←A[j]
          C[A[j]]← C[A[j]] -1

        b.基数排序

           1)背景

               基数排序是指用多关键字的“最低位优先”方法排序,即对待排序的记录序列按照关键字从低位到高位的顺序交替地进行“分组”,“收集”,最终得到有序的记录序列。将一次“分组”,“收集”称为一趟。对于由 d位关键字组成的复合关键字,需要经过d趟的“分配”与“收集”。 在基数排序的“分配”与“收集”操作过程中,为了避免数据元素的大量移动,通常采用链式存储结构存储待排序的记录序列 。

               适用于:要求对n个数的序列L={a1, a2 , …,an}进行排序,其中每个数恰好由k位数字组成,每位数字均取自{0,1,…,9}。  

           2)过程

                基数排序的“分配”与“收集”过程 第一趟 :

                

                基数排序的“分配”与“收集”过程 第二趟 :

                 

                 基数排序的“分配”与“收集”过程 第三趟 :

                   

                 3)特点              

                      基数排序适用于待排序的记录数目较多,但其关键字位数较少,且关键字每一位的基数相同的情况.若待排序记录的关键字有d位就需要进行d次"分配"与"收集",即共执行d趟,因此,若d值较大,基数排序的时间效率就会随之降低.基数排序是一种稳定的排序方法.

           c.桶排序

              1)背景

                   桶排序的思想是把[0,1)划分为n个大小相同的子区间,每一子区间是一个桶。然后将n个记录分配到各个桶中。因为关键字序列是均匀分布在[0,1)上的,所以一般不会有很多个记录落入同一个桶中。由于同一桶中的记录其关键字不尽相同,所以必须采用关键字比较的排序方法(通常用插入排序)对各个桶进行排序,然后依次将各非空桶中的记录连接(收集)起来即可。

              2)适用于

                   这种排序思想基于以下假设:假设输入的n个关键字序列是随机分布在区间[0,1)之上。若关键字序列的取值范围不是该区间,只要其取值均非负,我们总能将所有关键字除以某一合适的数,将关键字映射到该区间上。但要保证映射后的关键字是均匀分布在[0,1)上的。

              3)过程

                   

               4)代码                

      Bucket-Sort(A)
     {
          n=length[A]
          for(i=1;i<=n;i++) //分配过程.
          将A[i]插入到桶B[「n(A[i].key)」]中; 
          for(i=0;i<n;i++) //排序过程当B[i]非空时用插人排序将B[i]中的记录排序;
          for(i=0;i<n;i++) //收集过程若B[i]非空,则将B[i]中的记录依次输出到R中; 
    }

    各种算法总结

             

    二.查找

    方法:二分查找

    a.背景-给定已按升序排好序的n个元素a[1:n],现要在这n个元素中找出一特定元素x。

    b.分析-适用分治法求解问题的基本特征:

                    该问题的规模缩小到一定的程度就可以容易地解决;

                    该问题可以分解为若干个规模较小的相同问题;

                    分解出的子问题的解可以合并为原问题的解;

                    分解出的各个子问题是相互独立的。

                很显然此问题分解出的子问题相互独立,即在a[i]的前面或后面查找x是独立的子问题,因此满足分治法的第四个适用条件

    c.二分检索原理

                将二分检索问题问题表示为:I=(n, a1, … , an, x) 选取一个下标k,可得到三个子问题: I1=(k-1, a1, … , ak-1, x) I2=(1, ak , x) I3=(n-k, ak+1, … , an, x)

    d.问题描述

       已知一个按非降次序排列的元素表a1,a2,…,an,判定某个给定元素x是否在该表中出现,若是,则找出该元素在表中的位置,并置于j,否则,置j为0。

       一般解决办法:从小标0到最后依次查找,成功和不成功最坏情况下需要O(n)。

    e.二分搜索算法代码    

     1 public static int binarySearch(int [] a, int x, int n)
     2 {
     3   // 在 a[0] <= a[1] <= ... <= a[n-1] 中搜索 x
     4   // 找到x时返回其在数组中的位置,否则返回-1
     5   int left = 0; int right = n - 1;
     6   while (left <= right)
     7  { 
     8      int mid = (left + right)/2; // mid = low + ((high - low) / 2); 
     9      if (x == a[mid]) return mid;
    10      if (x > a[mid]) left = mid + 1;
    11      else right = mid - 1;
    12   }
    13   return -1; // 未找到x
    14 }

    二分搜索递归代码

     1 //初始 left = 0; right = N - 1;
     2 public static int binarySearch(int a[], int x, int left ,int right)
     3 {
     4    // 找到x时返回其在数组中的位置,否则返回-1
     5    if (left>right) return -1;// 未找到x
     6    else
     7    {
     8        int mid = (left + right)/2; 
     9        if (x == a[mid])   return mid;
    10        if (x > a[mid])   return binarySearch(a, x, mid+1,right);
    11        else return binarySearch( a,x,left,mid-1);
    12    }
    13 }

    f.二分搜索的时间复杂度

      若n在区域[2k-1, 2k)中,则对于一次成功的检索,二分检索算法至多作k次比较。

  • 相关阅读:
    SQL语句字符串处理大全
    iframe的属性
    The GridView 'gv ' fired event RowEditing which wasn 't handled.
    parttime job
    一个女孩如何准备行装和安全的独自旅行
    DORADO展现中间件的实现
    在asp.net 2.0中使用自定义的provider (转)
    MemberShip 的使用介绍(转)
    DBHelper
    jQuery学习——介绍演示网站
  • 原文地址:https://www.cnblogs.com/Mrs-cc/p/3391259.html
Copyright © 2011-2022 走看看