经典的7种排序算法 原理C++实现

经典的7种排序算法 原理C++实现

排序是编程过程中经常遇到的操作,它在很大程度上影响了程序的执行效率。

7种常见的排序算法大致可以分为两类:第一类是低级排序算法,有选择排序、冒泡排序、插入排序;第二类是高级排序算法,有堆排序、排序树、归并排序、快速排序。

一、低级排序算法

1. 选择排序

排序过程:给定一个数值集合,循环遍历集合,每次遍历从集合中选择出最小或最大的放入集合的开头或结尾的位置,下次循环从剩余的元素集合中遍历找出最小的并如上操作,最后直至所有原集合元素都遍历完毕,排序结束。

实现代码

//选择排序法

template

void Sort::SelectSort(T* array, int size)

{

int minIndex;

for(int i = 0; i < size; i++)

{

minIndex = i;

for(int j = i + 1; j < size; j++)

{

if(array[minIndex] > array[j])

{

minIndex = j;

}

}

if(minIndex != i)

{

Swap(array, i, minIndex);

}

}

}

分析总结:选择排序时间复杂度比较高,达到了O(n^2),每次选择都要遍历一遍无序区间。选择排序对一类重要的元素序列具有较好的效率,就是元素规模很大,而排序码却比较小的序列。另外要说明的是选择排序是一种不稳定的排序方法。

2. 冒泡排序

排序过程:冒泡排序的过程形如其名,就是依次比较相邻两个元素,优先级高(或大或小)的元素向后移动,直至到达序列末尾,无序区间就会相应地缩小。下一次再从无序区间进行冒泡操作,依此循环直至无序区间为1,排序结束。

实现代码:

//冒泡排序法

template

void Sort::BubbleSort(T* array, int size)

{

for(int i = 0; i < size; i++)

{

for(int j = 1; j < size - i; j++)

{

if(array[j] < array[j - 1])

{

Swap(array, j, j - 1);

}

}

}

}

分析总结:冒泡排序的时间复杂度也比较高,达到O(n^2),每次遍历无序区间都将优先级高的元素移动到无序区间的末尾。冒泡排序是一种稳定的排序方式。

3. 插入排序

排序过程:将前面的区间(初始区间为1,包含第一个元素)视作有序区间,然后将有序区间的后一元素插入到前面有序区间的适当位置。直至有有序区间扩展到原区间的大小,排序结束。

实现代码:

//插入排序

template

void Sort::InsertSort(T* array, int size)

{

for(int i = 1; i < size; i++)

{

for(int j = i; j > 0; j--)

{

if(array[j] < array[j - 1])

{

Swap(array, j, j-1);

}

}

}

}

分析总结:插入排序的时间复杂度达到O(n^2),排序的运行时间和待排序元素的原始排列顺序密切相关。插入排序是一种稳定的排序方法。

二、高级排序算法

1. 快速排序

排序过程:快速排序应该是应用最广泛的排序算法,它是采用了分治的思想(这种思想很重要)。其基本的思想就是任取待排序序列中的某个元素(元素的选取方式在一定程序上会影响实现过程和排序效率)作为标杆,将待排序序列划分为左右两个子序列,左侧元素小于标杆元素,右侧元素大于标杆元素,标杆元素则排在这两个子序列的中间,然后再对这两个子序列重复上述的方法,直至排序结束。

实现代码:

//快速排序

template

void Sort::QuickSort(T *array, int left, int right)

{

if(left < right)

{

int i = left -1, j = right + 1;

T mid = array[(left + right) / 2];

while(true)

{

while(array[++i] < mid);

while(array[--j] > mid);

if(i >= j)

{

break;

}

Swap(array, i, j);

}

QuickSort(array, left, i - 1);

QuickSort(array, j + 1, right);

}

}

分析总结:快速排序的时间复杂度为O(nlogn),是一种不稳定的排序算法。

2. 归并排序

排序过程:归并排序的原理比较简单,也是基于分治思想的。它将待排序的元素序列分成两个长度相等的子序列,然后为每一个子序列排序,然后再将它们合并成一个序列。

实现代码:

//归并排序

template

void Sort::MergeSort(T* array, int left, int right)

{

if(left < right)

{

int mid = (left + right) / 2;

MergeSort(array, left, mid);

MergeSort(array, mid + 1, right);

Merge(array, left, mid, right);

}

}

//合并两个已排好序的子链

template

void Sort::Merge(T* array, int left, int mid, int right)

{

T* temp = new T[right - left + 1];

int i = left, j = mid + 1, m = 0;

while(i <= mid && j <= right)

{

if(array[i] < array[j])

{

temp[m++] = array[i++];

}

else

{

temp[m++] = array[j++];

}

}

while(i <= mid)

{

temp[m++] = array[i++];

}

while(j <= right)

{

temp[m++] = array[j++];

}

for(int n = left, m = 0; n <= right; n++, m++)

{

array[n] = temp[m];

}

delete temp;

}

分析总结:归并排序最好、最差和平均时间复杂度都是O(nlogn),是一种稳定的排序算法。

3. 堆排序

排序过程:堆排序的过程分为两个步骤,第一步是根据初始输入数据,建立一个初始堆;第二步是将堆顶元素与当前无序区间的最后一个元素进行交换,然后再从堆顶元素开始对堆进行调整。

实现代码:

//堆排序

template

void Sort::HeapSort(T* array, int size)

{

int lastP = size / 2;

//从最后一个有孩子的结点开始建初始堆

for(int i = lastP - 1; i >= 0; i--)

{

HeapAjust(array, i, size);

}

int j = size;

//将堆顶元素和无序区间的最后一个元素交换,再调整堆

while(j > 0)

{

Swap(array, 0, j - 1);

j--;

HeapAjust(array, 0, j);

}

}

//调整堆

template

void Sort::HeapAjust(T *array, int toAjust, int size)

{

int pos = toAjust;

while((pos * 2 + 1) < size)

{

int lChild = pos * 2 + 1;

if(array[lChild] > array[pos])

{

pos = lChild;//左孩子大

}

int rChild = lChild + 1;

if(rChild < size && array[rChild] > array[pos])

{

pos = rChild;//右孩子更大

}

if(pos != toAjust) //父结点比其中一个孩子小

{

Swap(array, toAjust, pos);

toAjust = pos;

}

else

{

break;

}

}

}

分析总结:堆排序的算法时间复杂度为O(nlogn),它是一种不稳定的排序算法。

4. 排序树

排序过程:排序树算法应用了AVL树的原理,只不过排序树不是平衡的,它的特点就是父结点元素总是比左孩子元素要大却比右孩子元素要小。根据这个特点,可以将原数组元素组织成排序树,然后在对排序树进行中序遍历,中序遍历的结果就是排好序的序列。在算法的实现中采用的数组的形式来存储排序树,并采用的三个辅助数组来表示元素与元素之间在树中的关系,这三个辅助数组分别是父结点索引表、左孩子索引个、右孩子索引表。最后采用了递归的方法对排序树进行了中序遍历。

实现代码:

template

void Sort::TreeSort(T* array, int size)

{

int *parent = new int[size];//父结点子针

int *lChild = new int[size];//左孩子子针

int *rChild = new int[size];//右孩子子针

//将各结点左右子结点指针均置为-1,表示没有左右子结点

for(int i = 0; i < size; i++)

{

lChild[i] = -1;

rChild[i] = -1;

}

parent[0] = -1; //将第一个元素作为根结点,其父结点置为-1

//从第2个数开始构造树

for(int i = 1; i < size; i++)

{

int last = 0;

while(true)

{

int compare = array[i] - array[last];

if(compare > 0) //比当前值大,进入右子树

{

if(rChild[last] == -1)

{

rChild[last] = i;

parent[i] = last;

break;

}

else

{

last = rChild[last];

}

}

else //比当前值小,进入左子树

{

if(lChild[last] == -1)

{

lChild[last] = i;

parent[i] = last;

break;

}

else

{

last = lChild[last];

}

}

}

}

//保存排序树的中序遍历结果

T* midRetrival = new T[size];

TreeMidRetrival(array, midRetrival, 0, lChild, rChild);

//将排好序的中序数组复制到原数组

for(int i = 0; i < size; i++)

{

array[i] = midRetrival[i];

}

}

//中序遍历

template

void Sort::TreeMidRetrival(T *array, T* temp, int pos, T* lChild, T* rChild)

{

static int i = 0;

if(pos != -1)

{

TreeMidRetrival(array, temp, lChild[pos], lChild, rChild);//遍历左子树

temp[i++] = array[pos];//保存当前值

TreeMidRetrival(array, temp, rChild[pos], lChild, rChild);//遍历右子树

}

else

{

return;

}

}

分析总结:算法中排序树建立的时间复杂度是O(nlogn),中序遍历的时间复杂度是O(n),故排序树排序的时间复杂度为O(nlogn)。排序树的空间复杂度比较高,因为它使用了几个额外的存储空间的存储排序树元素之间的关系。

模板类定义如下所示:

template

class Sort

{

public:

void SelectSort(T* array, int size);

void InsertSort(T* array, int size);

void BubbleSort(T* array, int size);

void MergeSort(T* array, int left, int right);

void Merge(T* array, int left, int mid, int right);

void HeapSort(T *array, int size);

void HeapAjust(T *array, int toAjust, int size);

void QuickSort(T *array, int left, int right);

void TreeSort(T *array, int size);

void TreeMidRetrival(T* array, T* temp, int pos, T* lChild, T* rChild);

void Swap(T* array, int x, int y);

};

template //交换两个元素

void Sort::Swap(T* array, int x, int y)

{

T temp = array[x];

array[x] = array[y];

array[y] = temp;

}

时间: 2024-11-05 09:19:18

经典的7种排序算法 原理C++实现的相关文章

经典的两种排序算法

一.冒泡排序 int temp = 0; for (int j = 1; j < a.Length; j++) { for (int i = 0; i < a.Length - j; i++)//内循环,每走一趟会把最小值放到最后 { if (a[i] < a[i + 1]) { temp = a[i]; a[i] = a[i + 1]; a[i + 1] = temp; } } } 二.选择法排序 int min; for (int j = 0; j< a.Length; j++

12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用

出处:http://blog.csdn.net/han_xiaoyang/article/details/12163251. 声明:版权所有,转载请注明出处,谢谢. 0.前言 从这一部分开始直接切入我们计算机互联网笔试面试中的重头戏算法了,初始的想法是找一条主线,比如数据结构或者解题思路方法,将博主见过做过整理过的算法题逐个分析一遍(博主当年自己学算法就是用这种比较笨的刷题学的,囧),不过又想了想,算法这东西,博主自己学的过程中一直深感,基础还是非常重要的,很多难题是基础类数据结构和题目的思想综

13种排序算法详解

0.前言 从这一部分开始直接切入我们计算机互联网笔试面试中的重头戏算法了,初始的想法是找一条主线,比如数据结构或者解题思路方法,将博主见过做过整理过的算法题逐个分析一遍(博主当年自己学算法就是用这种比较笨的刷题学的,囧),不过又想了想,算法这东西,博主自己学的过程中一直深感,基础还是非常重要的,很多难题是基础类数据结构和题目的思想综合发散而来.比如说作为最基本的排序算法就种类很多,而事实上笔试面试过程中发现掌握的程度很一般,有很多题目,包括很多算法难题,其母题或者基本思想就是基于这些经典算法的,

总结N种排序算法及实现

排序算法是一个简单的问题,但在此问题上却有大量的研究!当前的排序算法通常按照如下四个方面进行分类(或是评价): 1.时间复杂度:一个排序算法的理想性能是O(n).一般而言,好的性能O(nlogn),坏的性能O(n2). 2.空间复杂度(内存使用量) 3.稳定性:稳定的排序算法会让原本有相等键值的记录维持原本的相对次序. 4.排序方式:插入.交换.选择.合并等 一.冒泡排序:这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端. 步骤:1.比较相邻的两个元素,如果第一个比第二个大,就

四种排序算法PHP实现类

四种排序算法的PHP实现:1) 插入排序(Insertion Sort)的基本思想是: 每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止. 2) 选择排序(Selection Sort)的基本思想是: 每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕. 3) 冒泡排序的基本思想是: 两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止. 4) 快速排序实质上和

几种排序算法的学习,利用Python和C实现

之前学过的都忘了,也没好好做过总结,现在总结一下. 时间复杂度和空间复杂度的概念: 1.空间复杂度:是程序运行所以需要的额外消耗存储空间,一般的递归算法就要有o(n)的空间复杂度了,简单说就是递归集算时通常是反复调用同一个方法,递归n次,就需要n个空间. 2.时间复杂度:一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多.一个算法中的语句执行次数称为语句频度或时间频度.记为T(n).一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)

Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排序.快速排序(重点).堆排序.归并排序等等.看下图: 给定数组:int data[] = {9,2,7,19,100,97,63,208,55,78} 一.直接插入排序(内部排序.O(n2).稳定) 原理:从待排序的数中选出一个来,插入到前面的合适位置. [java] view plain copy

常见的几种排序算法-插入、选择、冒泡、快排、堆排等

排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排序.快速排序(重点).堆排序.归并排序等等.看下图: 给定数组:int data[] = {9,2,7,19,100,97,63,208,55,78} 一.直接插入排序(内部排序.O(n2).稳定) 原理:从待排序的数中选出一个来,插入到前面的合适位置. package com.xtfggef.algo.sort; public

十大排序算法(原理及代码实现细节)

本文参考一些书籍啊哈算法,数据结构与算法(清华大学),已经一些网上的博客 然后动图也是从网上偷来的(^_^),代码实现我尽量用大家容易懂的方式实现 数组居多,然后,桶排序(是别人代码,不过写的不完全正确后面会更新),都是学习嘛 有误的地方,还望各位指正,希望对你有帮助(其实很灵活的,在运用上),也不要这样就满足了 多多地运用,会使理解更深的. 按上面的顺序来吧 原理在代码里直接上动图吧 冒泡排序动图演示 冒泡排序代码实现 1 #include<iostream> 2 #include<c