数据结构(十二)——排序算法

数据结构(十二)——排序算法

一、排序简介

1、排序的一般定义

排序是计算机中经常进行的操作,目的在于将一组无序的数据元素调整为有序的数据元素。
序列:1,20,45,5,2,12
排序后:1,2,5,12,20,45

2、排序的数学定义

3、排序的稳定性

如果序列中的两个元素R[i]、R[j],关键字分别为K[i]、K[j],并且在排序之前R[i]排在R[j]前面,如果排序操作后,元素R[i]仍然排在R[j]前面,则排序方法是稳定的;否则排序是不稳定的。

4、排序实现的关键

比较:任意两个数据元素通过比较操作确定先后次序。
交换:数据元素需要交换才能得到预期的结果。

5、排序算法的性能评价

A、时间性能
主要性能差异体现在比较和交换的数量
B、辅助存储空间
为完成排序操作需要的额外的存储空间
必要时可以空间换时间
C、算法的实现复杂性
过于复杂的排序算法影响可读性和可维护性

6、排序类

 class Sort:public Object
  {
  private:
    Sort();
    Sort(const Sort& other);
    Sort& operator = (const Sort& other);
    template <typename T>
    static void Swap(T& a, T& b)
    {
      T temp;
      temp = a;
      a = b;
      b = temp;
    }
  }

二、选择排序

1、选择排序简介

每次(第i次,i=1,2,3,...,n-2)从后面n-i个待排序的数据元素中选出关键字最小的元素,作为有序序列的第i个元素。
第i次选择排序示例:

选择排序实例:

2、选择排序的实现

选择排序的实现:

 /******************************************
     * 排序方式:选择排序
     * array:序列
     * len:序列中元素个数
     * min2max:按从小到大进行排序
     * ***************************************/
    template <typename T>
    static void Select(T array[], int len, bool min2max = true)
    {
      for(int i = 0; i < len; i++)
      {
          int min = i;//从第i个元素开始
          //对待排序的元素进行比较
          for(int j = i + 1; j < len; j++)
          {
              //按排序的方式选择比较方式
              if(min2max?(array[min] > array[j]):(array[min] < array[j]))
              {
                  min = j;
              }
          }
          if(min != i)
          {
             //元素交换
             Swap(array[i], array[min]);
          }
      }
    }

选择排序的时间复杂度为O(n^2)。
选择排序是不稳定的排序方法。

三、插入排序

1、插入排序简介

当插入第i(i>=1)个元素时,前i-1个元素已经排序好,用第i个元素的关键字与前i-1个元素的关键字分别进行比较,找到位置后将第i个元素插入,原来位置上的元素向后顺移。
第i次插入排序示例:

插入排序实例:


2、插入排序的实现

/******************************************
 * 排序方式:插入排序
 * array:序列
 * len:序列中元素个数
 * min2max:按从小到大进行排序
 * ***************************************/
template <typename T>
static void Insert(T array[], int len, bool min2max = true)
{
    for(int i = 1; i < len; i++)
    {
            int k = i;
            T temp = array[i];
            for(int j = i -1; (j > 0) && (min2max?(array[j] > temp):(array[j] < temp)); j--)
            {
                    array[j + 1] = array[j];
                    k = j;
            }
            if(k != i)
            {
                    array[k] = temp;
            }
    }
}

插入排序的时间复杂度为O(n^2)
插入排序是稳定的排序方法。

四、冒泡排序

1、冒泡排序简介

每次从后向前进行(第i次),j=n-1,n-2,...,i,比较V[j-1]和V[j]的关键字,如果发生逆序,则交换V[j-1]和V[j]。
第i次冒泡排序示例:

冒泡排序实例:

2、冒泡排序的实现

/**********************************************
 * 排序方式:冒泡排序
 * array:序列
 * len:序列中元素个数
 * min2max:按从小到大进行排序
 * *******************************************/
template <typename T>
static void Bubble(T array[], int len, bool min2max = true)
{
        bool exchange = true;
        //遍历所有元素
        for(int i = 0; (i < len) && exchange; i++)
        {
                exchange = false;
                //将尾部元素与前面的每个元素作比较交换
                for(int j = len - 1; j > i; j--)
                {
                        if(min2max?(array[j] < array[j-1]):(array[j] > array[j-1]))
                        {
                                //交换元素位置
                                Swap(array[j], array[j-1]);
                                exchange = true;
                        }
                }
        }
}

冒泡排序的时间复杂度为O(n^2)
冒泡排序是稳定的排序方法。

五、希尔排序

1、希尔排序简介

将待排序序列划分为若干组,在每一组内进行插入排序,以使整个序列基本有序,然后再对整个序列进行插入排序。
将n个数据元素分成d个子序列,划分方法如下:

d为增量,d的值在排序过程中由大到小逐渐缩小,直至最后一趟排序减为1。


2、希尔排序的实现

/******************************************
 * 排序方式:希尔排序
 * array:序列
 * len:序列中元素个数
 * min2max:按从小到大进行排序
 * ***************************************/
template <typename T>
static void Shell(T array[], int len, bool min2max = true)
{
        int d = len;
        do
        {
             d = d/3 + 1;
             for(int i = d; i < len; i += d)
             {
                     int k = i;
                     T temp = array[i];
                     for(int j = i -d; (j >= 0) && (min2max?(array[j] > temp):(array[j] < temp)); j -= d)
                     {
                             array[j+d] = array[j];
                             k = j;
                     }
                     if(k != i)
                     {
                                array[k] = temp;
                     }
             }
        }while(d > 1);
}
};

希尔排序通过分组的方法进行多次插入排序,是一种不稳定的排序方法,时间复杂度为O(n^(3/2))。

六、归并排序

1、归并排序简介

将两个或两个以上的有序序列合并成一个新的有序序列。

将2个有序序列归并为一个新的有序序列,称为2路归并。
将N个有序序列归并为一个新的有序序列,称为N路归并。
2路归并实例:

2、归并排序实现

template <typename T>
static void Merge(T src[], T helper[], int begin, int mid, int end, bool min2max=true)
{
        int i = begin;
        int j = mid + 1;
        int k = begin;
        while((i <= mid) && (j <= end))
        {
                if(min2max ? (src[i] < src[j]) : (src[i] > src[j]))
                {
                        helper[k++] = src[i++];
                }
                else
                {
                        helper[k++] = src[j++];
                }
        }
        while(i <= mid)
        {
                 helper[k++] = src[i++];
        }
        while(j <= end)
        {
                 helper[k++] = src[j++];
        }
        //拷贝辅助空间的结果到源序列空间
        for(i = begin; i <= end; i++)
        {
                src[i] = helper[i];
        }
}
template <typename T>
static void Merge(T src[], T helper[], int begin, int end, bool min2max=true)
{
        if(begin < end)
        {
                int mid = (begin + end) / 2;
                //左边路进行归并排序
                Merge(src, helper, begin, mid, min2max);
                //右边路进行归并排序
                Merge(src, helper, mid+1, end, min2max);
                //二路归并排序
                Merge(src, helper, begin, mid, end, min2max);
        }
}
/******************************************
* 排序方式:归并排序
* array: 序列
* len:序列中元素个数
* min2max:按从小到大进行排序
* ***************************************/
template <typename T>
static void Merge(T* array, int len, bool min2max=true)
{
    //辅助空间申请
    T* helper = new T[len];
    if(helper != NULL)
    {
        Merge(array, helper, 0, len-1, min2max);
    }
    delete [] helper;
}

归并排序是一种稳定排序,需要额外的辅助空间完成,空间复杂度为O(n),时间复杂度为O(nlogn)。

七、快速排序

1、快速排序简介

任取序列中的某个数据元素作为基准将整个序列划分为左右两个子序列。左侧子序列中所有的数据元素都小于或等于基准元素,右侧子序列中所有元素都大于基准元素,基准元素排在两个子序列中间。
分别对两个子序列进行重新划分,直到所有的数据元素都排在相应位置上为止。
快速排序示例:

快速排序实例:

2、快速排序实现

/******************************************
 * 快速排序的区域划分函数
 * array:序列
 * begin:序列的起始位置
 * end:序列的结束位置
 * min2max:按从小到大进行排序
 * ***************************************/
template <typename T>
static int Partition(T array[], int begin, int end, bool min2max)
{
        T pv = array[begin];
        while(begin < end)
        {
                while((begin < end) && (min2max ? (array[end] > pv): (array[end] < pv)))
                {
                        end--;
                }
                Swap(array[begin], array[end]);
                while((begin < end) && (min2max ? (array[end] <= pv): (array[end] > pv)))
                {
                        begin++;
                }
                Swap(array[begin], array[end]);
        }
        array[begin] = pv;
        return begin;
}

/******************************************
 * 快速排序功能函数
 * array: 序列
 * begin:序列的起始位置
 * end: 序列的结束位置
 * min2max:按从小到大进行排序
 * ***************************************/
template <typename T>
static void Quick(T array[], int begin, int end, bool min2max)
{
        if(begin < end)
        {
            //对序列进行区域划分
            int pivot = Partition(array, begin, end, min2max);
            //对基准左侧的区域进行快排序
            Quick(array, begin, pivot, min2max);
            //对基准右侧的区域进行块排序
            Quick(array, pivot+1, end, min2max);
        }
}
/******************************************
* 排序方式:快速排序
* array: 序列
* len:序列中元素个数
* min2max:按从小到大进行排序
* ***************************************/
template <typename T>
static void Quick(T array[], int len, bool min2max=true)
{
    Quick(array, 0, len-1, min2max);
}

快速排序通过递归的方式对排序问题重新划分,是一种不稳定的排序方法,时间复杂度为O(nlogn)。

八、排序的工程应用

1、排序算法面向数组类的实现

 template <typename T>
  static void Select(Array<T>& array, bool min2max=true)
  {
      Select(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Insert(Array<T>& array, bool min2max=true)
  {
      Insert(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Bubble(Array<T>& array, bool min2max=true)
  {
      Bubble(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Shell(Array<T>& array, bool min2max=true)
  {
      Shell(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Merge(Array<T>& array, bool min2max=true)
  {
      Merge(array.array(), array.length(), min2max);
  }

  template <typename T>
  static void Quick(Array<T>& array, bool min2max=true)
  {
      Quick(array.array(), array.length(), min2max);
  }

2、大规模序列的排序问题

排序过程中不可避免的需要进行交换操作,交换操作的本质为数据元素间的相互复制,如果序列的规模巨大时,交换操作将耗时巨大。
通过使用代理模式,为待排序元素设置代理对象,对代理对象组成的序列进行排序,需要访问有序序列元素时,通过访问待序列完成。
通过使用空间换时间提高算法效率。

原文地址:http://blog.51cto.com/9291927/2068735

时间: 2024-10-23 23:29:49

数据结构(十二)——排序算法的相关文章

12. 蛤蟆的数据结构进阶十二排序实现之直接插入法

12. 蛤蟆的数据结构进阶十二排序实现之直接插入法 本篇名言:"路是脚踏出来的 ,历史是人写出来的,人的每一步行动都在书定自己的历史. --吉鸿昌" 接下来看下直接插入法的实现. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47687631 1.  直接插入法 直接插入排序(straightinsertion sort) 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序. 第一趟比较前两

十大排序算法总结

排序算法术语说明 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面:不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面: 内排序:所有排序操作都在内存中完成:外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行: 时间复杂度: 一个算法执行所耗费的时间.空间复杂度: 运行完一个程序所需内存的大小. 排序算法图片总结(图片来源于网络) 图片名词解释:n: 数据规模k:"桶"的个数In-place: 占用常数内存,不占用额外内存

十大排序算法总结(Python3实现)

十大排序算法总结(Python3实现) 本文链接:https://blog.csdn.net/aiya_aiya_/article/details/79846380 目录 一.概述 二.算法简介及代码展示 1.冒泡排序 2.简单选择排序 3.简单插入排序 4.堆排序 5.快速排序 6.希尔排序 7.归并排序 8.计数排序 9.桶排序 10.基数排序 11.#代码说明 三.感悟总结 ________________________________________ 一.概述 排序算法大概是hello

十大排序算法--多图预警

十大排序算法 十大排序算法 简单的排序算法 插入排序 冒泡排序 选择排序 高效的比较排序算法 希尔排序 快速排序 归并排序 堆排序 牺牲空间的线性排序算法 计数排序 桶排序 基数排序 综合分析 简单的排序算法 Θ(n^2) 插入排序 动画演示 enter description here 原理 将数组看成两部分,一部分为已排序好的数组,后面的部分为未排序数组,每次从后面的数组中取出元素与前面的有序元素一一比较,若小于则向前移动,直到找到正确的位置插入.遍历后面的数组直到整个数组排序完成. 代码

十大排序算法整理(一):概览

十大排序算法分类.特点和关系 (1)冒泡排序(交换排序的一种) (2)选择排序 (3)插入排序 (4)归并排序(采用了分治思想,额外的空间复杂度O(N),容易记错,最后合并大数组的时候需要开辟一个长度为N的数组)  https://blog.csdn.net/u010452388/article/details/81008727 (5)快速排序(采用了分治思想,交换排序的一种,额外的空间复杂度O(NlogN),容易记错) 归并排序每次递归需要用到一个辅助表,长度与待排序的表相等,虽然递归次数是O

数据结构与算法系列十(排序算法概述)

1.引子 1.1.为什么要学习数据结构与算法? 有人说,数据结构与算法,计算机网络,与操作系统都一样,脱离日常开发,除了面试这辈子可能都用不到呀! 有人说,我是做业务开发的,只要熟练API,熟练框架,熟练各种中间件,写的代码不也能“飞”起来吗? 于是问题来了:为什么还要学习数据结构与算法呢? #理由一: 面试的时候,千万不要被数据结构与算法拖了后腿 #理由二: 你真的愿意做一辈子CRUD Boy吗 #理由三: 不想写出开源框架,中间件的工程师,不是好厨子 1.2.如何系统化学习数据结构与算法?

十大排序算法之(二)——冒泡排序

#1,简介 冒泡排序是一种比较基础.简单的排序算法,它的思想就是:key值较大的会像泡泡一样被你挑选出来向后或者向前移,这具体取决于你想要的结果数组是大序排列还是小序排列. 操作:对数组(或者其他存储结构)依次遍历,比较相邻两个元素,若与你设定的顺序相反,则交换位置,然后对数组要进行len-1次这样的遍历(len是数组长度). #2,c++实现 #include<iostream>#include<vector> using namespace std; void BubbleSo

(2)Java数据结构--二叉树 -和排序算法实现

=== 注释:此人博客对很多个数据结构类都有讲解-并加以实例 Java API —— ArrayList类 & Vector类 & LinkList类Java API —— BigDecimal类Java API —— BigInteger类Java API —— Calendar类Java API —— DateFormat类Java API —— Date类Java API —— HashMap类 & LinkedHashMap类Java API —— JDK5新特性Java

js十大排序算法详解

十大经典算法导图  图片名词解释:n: 数据规模k:"桶"的个数In-place: 占用常数内存,不占用额外内存Out-place: 占用额外内存 1.冒泡排序 1.1  原始人冒泡排序 function bubbleSort(arr) { var len = arr.length; for (var i = 0; i < len; i++) { for (var j = 0; j < len - 1 - i; j++) { if (arr[j] > arr[j+1]

js十大排序算法收藏

十大经典算法排序总结对比 一张图概括: 主流排序算法概览 名词解释: n: 数据规模k:“桶”的个数In-place: 占用常数内存,不占用额外内存Out-place: 占用额外内存稳定性:排序后2个相等键值的顺序和排序之前它们的顺序相同 冒泡排序(Bubble Sort) 冒泡排序须知: 作为最简单的排序算法之一,冒泡排序给我的感觉就像Abandon在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉...冒泡排序还有一种优化算法,就是立一个flag,当在一趟序列遍历中元素没有发生交换,