常用的排序算法C++
来源:互联网 发布:网络购彩何时恢复 编辑:程序博客网 时间:2024/06/07 00:48
排序算法:
- 冒泡排序
- 堆排序
- 归并排序
- 快速排序
- 希尔排序
- 直接插入排序
- 桶排序
- 基数排序
冒泡排序:
有n个数,先把相邻的两个数进行比较,大的数往后挪,大的数继续和后面相邻的数比较,重复n-1次,此时,最大的数在序列的尾部,不加入第二轮排序,故第二轮比较n-2次,以此类推。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,就不需要交换,因此冒泡排序是稳定排序算法。
冒泡排序最好的情况为一次循环,则复杂度为O(n),最坏的情况需要进行所有循环,即O(n^2)。
/* * 冒泡排序法:O(n^2) */#ifndef __BUBBLE_SORT_H__#define __BUBBLE_SORT_H__#include "swap.h"/** 有n个数,循环i = n-1次,a[j]和a[j+1]比,如果大于则交换两个数,j++直到j < (n-i-1)退出进入下个循环。*/template <class ElemType>void BubbleSort(ElemType e[], int n) {for (int i = 0; i < n - 1; i++) {for (int j = 0; j < (n - i - 1); j++) {if (e[j] > e[j + 1])Swap(e[j], e[j + 1]);}}}#endif // !__BUBBLE_SORT_H__
堆排序:
对n个数,先生成最大堆(或最小堆),然后把最大数放到尾部,对前面n-1个数继续进行最大堆排序,最大堆排序:从最后一个父节点开始,左右子节点做比较,大的节点与当前节点再做比较,当前节点比大的子节点小,则交换位置,继续比较倒数第二个父节点直到完成。如此循环直到完成排序。
平均时间复杂度:O(N*logN)。堆排序是不稳定的排序。
以 2, 15, 45, 76, 32, 6, 23 为例:
swap.h:
#ifndef __SWAP_H__#define __SWAP_H__template <class ElemType>void Swap(ElemType &e1, ElemType &e2) {ElemType e;e = e1;e1 = e2;e2 = e;}#endif
heap_sort.h:
/** 堆排序法:O(N*logN)*/#ifndef __HEAP_SORT_H___#define __HEAP_SORT_H___#include "swap.h"/* 1.先对整个数组进行堆排序(排序过程中先左子节点和右子节点比较,大的那个和当前节点交换) * 2.将排序好的最大堆的最大值与末端值调换,总共生成最大堆n-2次 */template <class ElemType>void HeapSort(ElemType elem[], int n) {int i;// 第一次需要对整个数组进行堆排序(从非子叶节点(n-2)/2开始向上移动)for (i = (n - 2) / 2; i >= 0; i--) {ComposeBigestHeap(elem, i, n - 1);}// 需要进行n-2次生成最大堆for (i = n - 1; i > 0; i--) {Swap(elem[0], elem[i]);// 之后的每次最大堆只要对elem[0]进行最大堆生成即可(因为除了elem[0]其余均已排好序)// 排序范围每次均要减去最下端已拍好的数ComposeBigestHeap(elem, 0, i - 1);}}template <class ElemType>void ComposeBigestHeap(ElemType elem[], int low, int high) {int cur, i;// cur为当前要生成最大堆的节点,i=2*i+1遍历向下的左子节点for (cur = low, i = 2 * low + 1; i <= high; i = 2 * i + 1) {// elem[i]为左子节点,elem[i+1]为右子节点,右子节点大的话,则指向右子节点继续向下if (i < high && elem[i] < elem[i + 1]) {i++;}// 如果当前节点值大于最大子节点,则不作后面操作if (elem[cur] >= elem[i]) {break;}Swap(elem[cur], elem[i]);cur = i;// 指向交换后的子节点}}#endif // !__HEAP_SORT_H___
归并排序:
将需要作比较的数列分成两份,再对分割出来的两份进行再分割,直到无法分割为止,接着在进行逐个比较合并。时间复杂度:O(n*logn) ,属于稳定的排序。
例子:
/** 归并排序法:O(n*log(n))*/#ifndef __MERGE_SORT_H___#define __MERGE_SORT_H___/* 归并主要关键在于先拆分,再合并 */template <class ElemType>void MergeSort(ElemType elem[], int n) {ElemType *telem = new ElemType[n];// 新建一个临时数组SperateTwoPart(elem, telem, 0, n - 1);delete []telem;}// 将数组分成无数份,直到不可分后,比较并合并template <class ElemType>void SperateTwoPart(ElemType elem[], ElemType telem[], int low, int high) {if (low < high) {int mid = (low + high) / 2;SperateTwoPart(elem, telem, low, mid);SperateTwoPart(elem, telem, mid + 1, high);Merge(elem, telem, low, mid, high);}}template <class ElemType>void Merge(ElemType elem[], ElemType telem[], int low, int mid, int high) {int i, j, k;for (i = low, j = mid + 1, k = low; i <= mid&&j <= high; k++) {// 比较,小的数值存储到临时数组中if (elem[i] > elem[j]) {telem[k] = elem[j];j++;}else {telem[k] = elem[i];i++;}}// 将归并后数组中剩余的数存储到临时数组中for (; i <= mid; i++, k++) {telem[k] = elem[i];}for (; j <= high; j++, k++) {telem[k] = elem[j];}// 将临时数组存回到原始数组for (i = low; i <= high; i++) {elem[i] = telem[i];}}#endif // !__MERGE_SORT_H___
快速排序:
以第一个数为基数key,所有数和key,大的放到右边,小的放到左边,再以key为中心,分成两部分。继续选择第一个数为key,按照前面的方法,直到排序完成。时间复杂度:n*log(n),属于不稳定的排序。
<pre name="code" class="cpp">/** 快速排序法:O(N*logN)*/#ifndef __QUICK_SORT_H__#define __QUICK_SORT_H__#include "swap.h"/* 快速排序,在数组取一个基准数,把大于基准数的数放置在右侧,小于在左侧。 * 再把基准数分隔开的两个部分继续取基准数分割。 */template <class ElemType>void QuickSort(ElemType elem[], int n) {SperateQuickPart(elem, 0, n - 1);}template <class ElemType>void SperateQuickPart(ElemType elem[], int low, int high) {if (low >= high)return;// pos为序列中的基准数int pos = Partition(elem, low, high);// 以基准数为中心,左右分开SperateQuickPart(elem, low, pos - 1);SperateQuickPart(elem, pos + 1, high);}template <class ElemType>int Partition(ElemType elem[], int low, int high) {int key = elem[low];while (low < high) {// 当左边的数小于右边,high--while (low < high && elem[high] >= key) {--high;}elem[low] = elem[high];while (low < high && elem[low] <= key) {++low;}elem[high] = elem[low];}elem[low] = key;// 返回基准数return low;}#endif // !__QUICK_SORT_H__
希尔排序:
属于稳定的排序。
(引用自百度百科):
不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(
/** 希尔插入排序法:最好O(n),最坏O(n^2)*/#ifndef __SHELL_SORT_H__#define __SHELL_SORT_H__/* 推理过程 * 6 5 4 3 2 1n=6 * 3 6 * 2 5 * 1 4 * 3 2 1 6 5 4n/2=3 * 2 3 * 1 3 * 3 6 * 5 6 * 4 6 * 2 1 3 5 4 6n/2=1 * 1 2 * 2 3 * 3 5 * 4 5 * 5 6 * 1 2 3 4 5 6n/2=0 */template <class ElemType>void ShellSort(ElemType elem[], int n) {for (int k = n / 2; k > 0; k /= 2){// 取中间数n/2for (int i = k; i < n; i++) {// i=n/2 且i++ElemType e = elem[i];int j = i;for (; j >= k && e < elem[j - k]; j -= k) {// elem[i]和elem[i-k]比较elem[j] = elem[j - k];}elem[j] = e;}}}#endif // !__SHELL_SORT_H__
直接插入排序:
/** 直接插入排序法:最好O(n),最坏O(n^2)*/#ifndef __STRAIGHT_INSERT_SORT_H__#define __STRAIGHT_INSERT_SORT_H__/** 有n个数,循环n-1次,从第二个数a[i](i=1)开始,和它前面一个数比,如果小于前面的数则交换两个数,不小于退出进入下个循环,* 下个循环从a[i+1]开始,和它前面一个数a[i]比,如果小于前面的数交换并且继续和a[i](i=i-1)比,直到不小于退出进入下个循环.*/template <class ElemType>void StraightInsertSort(ElemType elem[], int n) {for (int i = 1; i < n; i++) {ElemType e = elem[i];int j;for (j = i - 1; j >= 0 && e < elem[j]; j--) {elem[j + 1] = elem[j];// e前面的数后移}elem[j + 1] = e;//j+1=i即elem[j + 1]=elem[i]}}#endif // !__STRAIGHT_INSERT_SORT_H__
节点和链表类,为用链表排序做准备。
node.h:
<span style="font-size:18px;">#ifndef __NODE_H__#define __NODE_H__// 结点类template <class ElemType>struct Node {// 数据成员:ElemType data;// 数据域Node<ElemType> *next;// 指针域// 构造函数:Node();// 无参数的构造函数Node(ElemType item, Node<ElemType> *link = NULL);// 已知数数据元素值和指针建立结构};// 结点类的实现部分template<class ElemType>Node<ElemType>::Node()// 操作结果:构造指针域为空的结点{ next = NULL;}template<class ElemType>Node<ElemType>::Node(ElemType item, Node<ElemType> *link)// 操作结果:构造一个数据域为item和指针域为link的结点{ data = item; next = link;}#endif</span>
lk_list.h:
<span style="font-size:18px;">#ifndef __LK_LIST_H__#define __LK_LIST_H__#include "node.h"template <class ElemType>class LinkList{protected:Node<ElemType> *head;// 头结点指针mutable int cpos;// 当前位置的序号mutable Node<ElemType> * curPtr;// 指向当前位置的指针int count;// 元素个数Node<ElemType> *GetElemPtr(int position) const;// 返回指向第position个结点的指针void Init();// 初始化线性表public:LinkList();virtual ~LinkList();int Length() const; // 求线性表长度bool Empty() const;// 判断线性表是否为空void Clear();// 将线性表清空void Traverse() const;// 遍历线性表int GetCurPosition() const;// 返回当前位置bool GetElem(int position, ElemType &e) const;// 求指定位置的元素bool SetElem(int position, const ElemType &e);// 设置指定位置的元素值bool Delete(int position, ElemType &e);// 删除元素bool Insert(int position, const ElemType &e);// 插入元素LinkList(const LinkList<ElemType> ©); // 复制构造函数模板LinkList<ElemType> &operator =(const LinkList<ElemType> ©); // 重载赋值运算符};template <class ElemType>Node<ElemType> *LinkList<ElemType>::GetElemPtr(int position) const {if (cpos > position) {cpos = 0;curPtr = head;}for (; cpos < position; cpos++) {curPtr = curPtr->next;}return curPtr;}template <class ElemType>void LinkList<ElemType>::Init() {head = new Node<ElemType>;curPtr = head;cpos = 0;count = 0;}template <class ElemType>LinkList<ElemType>::LinkList(){Init();}template <class ElemType>LinkList<ElemType>::~LinkList(){delete head;}template <class ElemType>int LinkList<ElemType>::Length() const// 操作结果:返回线性表元素个数{return count;}template <class ElemType>bool LinkList<ElemType>::Empty() const {return head->next == NULL;}template <class ElemType>void LinkList<ElemType>::Clear() {ElemType e;while (Length() > 0){Delete(1, e);}}template <class ElemType>void LinkList<ElemType>::Traverse() const {for (Node<ElemType> *n = head->next; n != NULL; n = n->next) {cout << n->data << " ";}cout << endl;}template <class ElemType>int LinkList<ElemType>::GetCurPosition() const {return cpos;}template <class ElemType>bool LinkList<ElemType>::GetElem(int position, ElemType &e) const {if (position < 1 || position > Length()){// position范围错return false;// 元素不存在}else {Node<ElemType> *n;n = GetElemPtr(position);e = n->data;return true;}}template <class ElemType>bool LinkList<ElemType>::SetElem(int position, const ElemType &e) {if (position < 1 || position > Length()){// position范围错return false;// 元素不存在}else {Node<ElemType> *n;n = GetElemPtr(position);n->data = e;return true;}}template <class ElemType>bool LinkList<ElemType>::Delete(int position, ElemType &e) {if (position < 1 || position > Length()){// position范围错return false;// 元素不存在}else {Node<ElemType> *n;n = GetElemPtr(position - 1);Node<ElemType> *nn = n->next;// nn为n的下一个后继节点n->next = nn->next;e = nn->data;if (position == Length()) {cpos = 0;curPtr = head;}else {cpos = position;curPtr = n->next;}count--;delete nn;return true;}}template <class ElemType>bool LinkList<ElemType>::Insert(int position, const ElemType &e) {if (position < 1 || position > Length() + 1){// position范围错return false;// 元素不存在}else {Node<ElemType> *n;n = GetElemPtr(position - 1);Node<ElemType> *newn;newn = new Node<ElemType>(e, n->next);n->next = newn;cpos = position;curPtr = newn;count++;return true;}}template <class ElemType>LinkList<ElemType>::LinkList(const LinkList<ElemType> ©) {int copylen = copy.Length();ElemType e;Init();for (int cpos = 1; cpos <= copylen; cpos++) {copy.GetElem(cpos, e);Insert(Length() + 1, e);}cout << "调用拷贝构造函数" << endl;}template <class ElemType>LinkList<ElemType> &LinkList<ElemType>::operator = (const LinkList<ElemType> ©) {if (© != this) {int copylen = copy.Length();ElemType e;Clear();for (int cpos = 1; cpos <= copylen; cpos++) {copy.GetElem(cpos, e);Insert(Length() + 1, e);}}cout << "调用赋值函数" << endl;return *this;}#endif // !__LK_LIST_H__</span>
桶排序:
将需要排序的数放到有限个桶,然后按照桶排好的顺序收集数据,如若桶中的数据 > 1,则用其他优秀的算法进行排序(如快速排序等)。如果桶的数量恰好等于数的数量,则效率最好,为O(n),当然我们不可能这么做,因为对于数量庞大排序,消耗空间太大。假设n个数,有m个桶,则平均复杂度:O(n)+O( m*(n/m)*log(n/m) ) = O( n+n*(log n - log m) ),排序期间相等的数不会改变顺序,依次属于稳定排序。
<pre name="code" class="cpp">/** 桶排序法:平均:O(N+N*logN-N*logM),最好:O(N)*/#ifndef __BUCKET_SORT_H__#define __BUCKET_SORT_H__#include "lk_list.h"// n为数的个数,m为桶的个数template <class ElemType> void BucketSort(ElemType elem[], int n, int m){LinkList<ElemType> *list;// 用于存储被分配的线性表数组list = new LinkList<ElemType>[10];int num = Distribute(elem, n, m, list);// 分配SortList(list, n, num);// 对分配好的list逐一进行排序,这里可以选择先进的排序方法提高效率Colect(elem, n, list);// 收集delete[]list;}template <class ElemType>int Distribute(ElemType elem[], int n, int m, LinkList<ElemType> list[]){int num = 0;for (int i = 0; i < n; i++){// 进行第i起分配int index = elem[i] / m;// 将list视为桶,符合条件的数放入相应的桶中list[index].Insert(list[index].Length() + 1, elem[i]);if (num < index)num = index;}// 返回桶个数,进而对各个桶内的数据进行排序return num;}template <class ElemType>void SortList(LinkList<ElemType> *list, int n, int num){for (int i = 0; i < num; i++){// 对各个桶内的数据进行排序,这里可替换为高效的排序算法QuickSort(list[i], n);}}template <class ElemType>void Colect(ElemType elem[], int n, LinkList<ElemType> list[]){for (int k = 0, j = 0; j < 10; j++){// 进行第i起分配ElemType tmpElem;// 逐个桶按顺序收集数据while (!list[j].Empty()){// 收集list[j]list[j].Delete(1, tmpElem);elem[k++] = tmpElem;}}}#endif // !__BUCKET_SORT_H__
基数排序:
排序时,假设我们排序的数的范围在0~999之间,则关键码digits分为个位、十位、百位,共3个,基数r(关键字的取值范围)为0~9(10位)。
假设有n=7个数,为
33,2,65,312,98,9,120
根据基数分出10个桶,依照个位分别放入桶内
01 2 3 4 56 7 8 9
1202 33 65 98 9
312
排序后: 120, 2, 312, 33, 65, 98, 9
接着按照十位:2, 9, 312, 120, 33, 65, 98
百位: 2, 9, 33, 65, 98, 120, 312
时间复杂度:O( d*(r+n) ),其中d是关键码位数,r为基数,n为数的个数。且基数排序为稳定的排序。
radix_sort.h:/* * 基数排序法:O(n^2) */#ifndef __RADIX_SORT_H__#define __RADIX_SORT_H__#include "lk_list.h"template <class ElemType>void RadixSort(ElemType elem[], int n, int r){int digits;// d为关键字位数digits = NumOfDigits(elem, n);// 判断数组中的最高位并返回位数LinkList<ElemType> *list;// 用于存储被分配的线性表数组list = new LinkList<ElemType>[r];for (int i = 1; i <= digits; i++){// 第i趟分配与收集Distribute(elem, n, r, i, list);// 分配Colect(elem, n, r, list);// 收集}delete []list;}template <class ElemType>void Distribute(ElemType elem[], int n, int r, int i, LinkList<ElemType> list[])// 初始条件: r为基数,list[0 .. r - 1]为被分配的线性表数组// 操作结果: 进行第i趟分配{for (int power = (int)pow((double)r, i - 1), j = 0; j < n; j++){// 进行第i起分配int index = (elem[j] / power) % r;list[index].Insert(list[index].Length() + 1, elem[j]);}}template <class ElemType>void Colect(ElemType elem[], int n, int r, LinkList<ElemType> list[])// 初始条件: r为基数,list[0 .. r - 1]为被分配的线性表数组// 操作结果: 进行第i趟收集{for (int k = 0, j = 0; j < r; j++){// 进行第i起分配ElemType tmpElem;while (!list[j].Empty()){// 收集list[j]list[j].Delete(1, tmpElem);elem[k++] = tmpElem;}}}template <class ElemType>int NumOfDigits(ElemType elem[], int n){int largest = 0;for (int i = 0; i < n; i++) {if (elem[i] > largest)largest = elem[i];}int digits = 0;//digits为最大值的位数while (largest){digits++;largest /= 10;}return digits;}#endif
源代码:http://download.csdn.net/detail/u013707014/9032507
- C 语言常用的排序算法
- Objective-C实现常用的排序算法
- C 语言常用的排序算法
- 常用排序算法的C语言实现
- C 语言常用的排序算法
- 常用排序算法(C描述)
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 常用的排序算法
- 获得多行UILabel的每一行内容
- LeetCode(83)Remove Duplicates from Sorted List
- 怎么把pdf电子书转换成txt格式
- nodejs+ajax实现数据交互
- C 几个优化方法
- 常用的排序算法C++
- 4710zipperdfs
- 掌门人澄清电信与联通合并
- 一段自定义布局的源码分析
- 数据结构-----哈希表
- C# Serializable
- UE4 System Settings
- 数据结构与算法分析——二分查找
- 程序开发免费的接口