排序算法(一)

查找,也可称检索,是在大量的数据元素中找到某个特定的数据元素而进行的工作。查找是一种操作。

顺序查找

针对无序序列的一种最简单的查找方式。

时间复杂度为O(n)。

查找成功时的平均查找长度为:(假设每个数据元素的概率相等) ASL = (1+2+3+…+n)/n = (n+1)/2 ;

当查找不成功时,需要n+1次比较,时间复杂度为O(n);

优点: 
算法简单,且对表的结构无任何要求,无论是用向量还是用链表来存放结点,也无论结点之间是否按关键字有序,它都同样适用。

缺点: 
查找效率低,因此,当n较大时不宜采用顺序查找。

//顺序查找
int SequenceSearch(int a[], int value, int n)
{
    int i;
    for(i=0; i<n; i++)
        if(a[i]==value)
            return i;
    return -1;
}

二分查找

说明:元素必须是有序的,如果是无序的则要先进行排序操作。

基本思想:也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。

复杂度分析: 最坏情况下,关键词比较次数为log 2 (n+1),且 期望时间复杂度为O(log 2 n) ;

注: 折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,折半查找能得到不错的效率。但对于需要 频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用。——《大话数据结构

//二分查找(折半查找),迭代版
int BinarySearch1(int a[], int value, int n)
{
  int low, high, mid;
  low = 0;
  high = n-1;
  while(low<=high)
  {
    mid = (low+high)/2;
    if(a[mid]==value)
      return mid;
    if(a[mid]>value)
      high = mid-1;
    if(a[mid]<value)
      low = mid+1;
  }
  return -1;
}
//二分查找,递归版本
int BinarySearch2(int a[], int value, int low, int high)
{
  int mid = low+(high-low)/2;
  if(a[mid]==value)
    return mid;
  if(a[mid]>value)
    return BinarySearch2(a, value, low, mid-1);
  if(a[mid]<value)
    return BinarySearch2(a, value, mid+1, high);
}

插值查找(二分查找的改进)

在介绍插值查找之前,首先考虑一个新问题,为什么上述算法一定要是折半,而不是折四分之一或者折更多呢?

打个比方,在英文字典里面查“apple”,你下意识翻开字典是翻前面的书页还是后面的书页呢?如果再让你查“zoo”,你又怎么查?很显然,这里你绝对不会是从中间开始查起,而是有一定目的的往前或往后翻。

同样的,比如要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 我们自然会考虑从数组下标较小的开始查找。

经过以上分析,折半查找这种查找方式,不是自适应的(也就是说是傻瓜式的)。二分查找中查找点计算如下:

mid=(low+high)/2, 即mid=low+1/2*(high-low);

通过类比,我们可以将查找的点改进为如下:

mid=low+ (key-a[low])/(a[high]-a[low]) *(high-low)

也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。

基本思想: 基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,差值查找也属于有序查找。

注: 对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。

复杂度分析: 查找成功或者失败的时间复杂度均为O(log 2 (log 2 n))。

//插值查找
int InsertionSearch(int a[], int value, int low, int high)
{
  int mid = low+(value-a[low])/(a[high]-a[low])*(high-low);
  if(a[mid]==value)
    return mid;
  if(a[mid]>value)
    return InsertionSearch(a, value, low, mid-1);
  if(a[mid]<value)
    return InsertionSearch(a, value, mid+1, high);
}

分块查找

分块查找是将顺序查找与折半查找相结合的一种查找方法。

基本思想: 
1. 首先将查找表分成若干块,在每一块中数据元素的存放是任意的,但块与块之间必须是有序的(假设这种排序是按关键字值递增的,也就是说在第一块中任意一个数据元素的关键字都小于第二块中所有数据元素的关键字,第二块中任意一个数据元素的关键字都小于第三块中所有数据元素的关键字,依次类推); 
2. 建立一个索引表,把每块中最大的关键字值按块的顺序存放在一个辅助数组中,这个索引表也按升序排列; 
3. 查找时先用给定的关键字值在索引表中查找,确定满足条件的数据元素存放在哪个块中,查找方法既可以是折半方法,也可以是顺序查找。 
4. 再到相应的块中顺序查找,便可以得到查找的结果。

  图 1-2 所示为一个索引顺序表。其中包括三个块,第一个块的起始地址为 0,块内最大关键字为 25;第二个块的起始地址为 5,块内最大关键字为 58;第三个块的起始地址为10,块内最大关键字为 88。

  分块查找的基本过程如下:

  (1)首先,将待查关键字 K 与索引表中的关键字进行比较,以确定待查记录所在的

块。具体的可用顺序查找法或折半查找法进行。

  (2)进一步用顺序查找法,在相应块内查找关键字为 K的元素。

     / * 分块查找
     *
     * @param index 索引表,其中放的是各块的最大值
     * @param st 顺序表,
     * @param key 要查找的值
     * @param m 顺序表中各块的长度相等,为m
     * @return
     */
int BlockSearch(int[ ] index, int[ ] st, int key, int m)   //分块查找
    {
          //  在序列st数组中,用分块查找方法查找关键字为key的记录
         // 1.在index[ ] 中折半查找,确定要查找的key属于哪个块中
          int i = BinarySearch(index, key);
          if(i >= 0)
          {
              int j = i > 0 ? i * m : i;
              int len = (i + 1) * m;
              // 在确定的块中用顺序查找方法查找key
              for(int k = j; k < len; k++)
              {
                  if(key == st[k])
                  {
                      System.out.println("查询成功");
                      return k;
                  }
              }
           }
          System.out.println("查找失败");
          return -1;
    } 

    int BinarySearchs(int[] data, int tmpData)
    {
        int mid;
        int low = 0;
        int high = data.length - 1;
        while(low <= high)
        {
            mid = (low + high) / 2;     // 中间位置
            if(tmpData == data[mid])
            {
                return mid;
            }
            else if(tmpData < data[mid])
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
                return low;
            }
        }
        return -1;                // 没有查找到
  } 
时间: 2024-08-02 16:25:18

排序算法(一)的相关文章

经典排序算法 - 冒泡排序Bubble sort

 原文出自于 http://www.cnblogs.com/kkun/archive/2011/11/23/bubble_sort.html 经典排序算法 - 冒泡排序Bubble sort 原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换, 这样一趟过去后,最大或最小的数字被交换到了最后一位, 然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似看例子 例子为从小到大排序, 原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 | 第一趟排序(外循环) 第

排序算法比较及其应用

一.将各种数据排序 只要实现了Comparable接口的数据类型就可以被排序. 但要使算法能够灵活地用不同字段进行排序,则是后续需要考虑的问题. 1.指针排序 在Java中,指针操作是隐式的,排序算法操作的总是数据引用,而不是数据本身. 2.键不可变 如果在排序后,用例还可以改变键值,那么数组很可能就不是有序的了.类似,优先队列也会乱套. Java中,可以用不可变数据类型作为键来避免这个问题,如String,Integer,Double和File都是不可变的. 3.廉价交换 使用引用的另一个好处

选择排序 —— 排序算法系列

假设我们有如下一个数组: 使用选择排序算法对这个数组进行排序,步骤如下: 第 1 次 在下标0到6之间找到最小的数字,我们可以发现最小的数字是15,它在下标为4的位置上: 把下标4上面的数字跟下标0上面的数字互换,得到排序如下图的数组: 第 2 次 在下标1到6之间找到最小的数字,我们可以发现最小的数字是33,它在下标为5的位置上: 把下标5上面的数字跟下标1上面的数字互换,得到排序如下图的数组: 第 3 次 在下标2到6之间找到最小的数字,我们可以发现最小的数字是48,它在下标为5的位置上:

排序算法Java版,以及各自的复杂度,以及由堆排序产生的top K问题

常用的排序算法包括: 冒泡排序:每次在无序队列里将相邻两个数依次进行比较,将小数调换到前面, 逐次比较,直至将最大的数移到最后.最将剩下的N-1个数继续比较,将次大数移至倒数第二.依此规律,直至比较结束.时间复杂度:O(n^2) 选择排序:每次在无序队列中"选择"出最大值,放到有序队列的最后,并从无序队列中去除该值(具体实现略有区别).时间复杂度:O(n^2) 直接插入排序:始终定义第一个元素为有序的,将元素逐个插入到有序排列之中,其特点是要不断的 移动数据,空出一个适当的位置,把待插

排序算法总结

各种排序算法总结  排序算法  插入排序 冒泡排序  选择排序  归并排序  快速排序 堆排序  计数排序  基数排序  桶排序  思想  构建有序序列 两两交换 每次找一个最小值 分治法思想 分治法思想 最小堆.最大堆 数字本身的属性  对数据选择多种基数  函数的映射关系.Hash  数据结构  数组  数组  数组  数组 不定   数组 数组 数组  数组  最差时间复杂度 O(n^2)   O(n^2)   O(n^2)   O(n*lgn)  O(n^2).改进O(n*lgn)  O

七大常见排序算法总结

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.04.06 lutianfei none V1.1 2016.07.16 lutianfei 增加了归并排序说明 V2.0 2016.07.19 lutianfei 完善了排序算法的总结 排序另一种分法 外排序:需要在内外存之间多次交换数据才能进行 内排序: 插入类排序 直接插入排序 希尔排序 选择类排序 简单选择排序 堆排序 交换类排序 冒泡排序 快速排序 归并类排序 归并排序 排序方法 平均情况 最好情况 最坏情况

数据结构——各排序算法的比较

1.从时间复杂度比较  从平均时间复杂度来考虑,直接插入排序.冒泡排序.直接选择排序是三种简单的排序方法,时间复杂度都为O(n2),而快速排序.堆排序.二路归并排序的时间复杂度都为O(nlog2n),希尔排序的复杂度介于这两者之间.若从最好的时间复杂度考虑,则直接插入排序和冒泡排序的时间复杂度最好,为O(n),其它的最好情形同平均情形相同.若从最坏的时间复杂度考虑,则快速排序的为O(n2),直接插入排序.冒泡排序.希尔排序同平均情形相同,但系数大约增加一倍,所以运行速度将降低一半,最坏情形对直接

八种排序算法

最近一段时间自己在研究各种排序算法,于是自己写了一个八种排序算法的集合: /************************************************************************* > Copyright (c)2014 stay hungry,stay foolish !!! > File Name: sort.cpp > Author: kanty > Mail: [email protected] > Created Time:

排序算法 之 快速排序

快速排序是基于分治思想的一种排序算法,就像该方法的名字一样,速度比较快,所以叫做快速排序:它的平均时间复杂度为O(N*logN),最坏时间复杂度为O(n2),由于快速排序在序列元素数量多的时候速度比较快,所以很多语言内置的排序方法也是用快速排序实现的.快速排序也有很多优化的版本,比如在排序时基数的选择等等-下面就说一下一般的快速排序的实现. 基本思想: 快速排序的基本思想就是,先从待排序的序列中任选一个元素作为基数,然后将序列中的其他小于基数的元素放在基数的左边,大于或等于基数的元素放在基数的右

排序算法的JS实现

排序算法是基础算法,虽然关键在于算法的思想而不是语言,但还是决定借助算法可视化工具结合自己常用的语言实现一下 1.冒泡排序 基本思路:依次比较两两相邻的两个数,前面数比后面数小,不变.前面数比后面数大,交换顺序.一轮下来,最后的一个数是最大的数. 外循环每增加一次,内循环减少一次. 图形展示: function bubbleSort(arr){ for (var i = 0; i < arr.length; i++) { for (var j = 0; j< arr.length-i-1; j