排序算法总结

来源:互联网 发布:武汉壹方凌网络怎么样 编辑:程序博客网 时间:2024/06/02 13:18

1、有一点问题注意的就是, 排序算法中插入总会比冒泡式的交换更有效,所以希尔排序,在排序每组元素的时候总是会用到插入法排序, 而不是频繁的交换。

 

冒泡、简单选择、简单插入、希尔、堆、快速、归并、基数等8种排序算法的源代码, 测试过可以使用, 大家有什么更优秀的算法,也已在评论中给出, 我回时时更新的。

#ifndef SORT_FUNCTIONS#define  SORT_FUNCTIONS#include <queue>#include <algorithm>#include <vector>#include <exception>#include "s_heap.h"using namespace std;// 冒泡排序// 函数功能: 对向量中的数据进行冒泡排序// 后置条件: 向量已序template <typename T>void bubbleSort(vector<T>& v);// 基数排序, 算法将数字每个为从低位到高位进行逐位排序template <typename T>void radixSort(vector<T>& v, int d);// 选择排序向量template <typename T>void selectionSort(vector<T>& v);// 插入排序向量template <typename T>void insertionSort(vector<T>& v);// 对向量中的数据进行堆排序, 采用compare最为比较函数template <typename T, typename Compare>void heapSort(vector<T>& v, Compare comp);/* 归并排序   begin*///  向量的【first, mid)和【mid, last)部分是依序的,  利用归并发组合两部分,排序向量//后置条件: 整个向量是已序template <typename T>void merge(vector<T>& v, int first, int mid, int last);// 利用归并法排序整个向量// 后置条件: 整个向量已序template <typename T>void mergeSort(vector<T>& v, int first, int last);/* 归并排序   end  *//* 快速排序   begin  */// 找到向量的基准位置, 使得 位置之前的元素 <= 基准元素, 位置之后的元素大于基准元素template <typename T>int pivotIndex(vector<T>& v, int first, int last);// 快速法排序向量template <typename T>void quicksort(vector<T>& v, int first, int last);/* 快速排序   end  *//*基数排序// begin*///得到排序数字最大的限制的位数, 是几位数int Power(const int limitNumber);// 将向量中的每位数字插入到排序队列中template <typename T>void distribute(vector<T>& v, queue<T> q[10], int power);// 基数排序, 算法将数字每个为从低位到高位进行逐位排序template <typename T>void radixSort(vector<T>& v, int d);// 将各个队列中的元素按照刚刚拍好拍好一位的顺序插入向量中template <typename T>void collect(queue<T> q[10], vector<T>& v);/*基数排序end*/// 希尔排序template <typename T>void shellSort(vector<T>& v, const size_t first, const size_t last);///////////////////////////////////////////////////////////////函数实现///////////////////////////////////////////////////////// 冒泡排序template <typename T>void bubbleSort(vector<T>& v){// 记录最后一个元素和最后第二个元素, 增加算法的效率int last = v.size() - 1;for (int i = 0; i <last; i++){for (int j = last; j > i; -- j){if (v[j ] < v[j - 1])swap(v[j - 1], v[j]);}}}// 选择排序template <typename T>void selectionSort(vector<T>& v){// 记录最大下标方便交换int min;// 记录向量中元素的个数int n = v.size();// 遍历找向量最大元素, 放到 i 位置for (int i = 0; i < n - 1; ++i){// 将当前下标默认为最小值坐标, 然后从当前位置饿后一个位置开始找到最大下标min = i;for (int j = i + 1; j < n; ++j){if (v[j] < v[min])min = j;}// 如果最大的下标不是当前位置时, 进行交换if (min != i){swap(v[min], v[i]);}}}// 插入排序template <typename T>void insertionSort(vector<T>& v){// 记录向量的元素个数int n = v.size();// 从当前位置开始, 在它前面的元素是依序的, 找到当前位置的在依序中的合适位置, 插入for (int i = 1; i < n; i++){T target = v[i];// 找到当前元素应该在依序部分中的合适位置int j = i;while (j > 0 && target < v[j - 1]){v[j] = v[j - 1];j--;}// 将元素插入到找到的位置v[j] = target;}}// 堆排序template <typename T, typename Compare>void heapSort(vector<T>& v, Compare comp){// 使得向量对话makeHeap(v, comp);// 排序向量for (int i = v.size(); i > 1; --i){popHeap(v, i, comp);}}/*    归并排序begin*/template <typename T>void merge(vector<T>& v, int first, int mid, int last){// 临时向量,存数临时以序表vector<T> tempVec;// 开始记录变量, 对向量中【first,mid)和【mid, last) 区间的元素进行排序,// 遍历两个自己,选择较小的元素, 插入临时向量中int indexA = first,indexB = mid;// 遍历子表中, 当两个子表都不为空时while (indexA < mid && indexB < last){// 将子表中较小的元素插入临时向量中if (v[indexA] < v[indexB])tempVec.push_back(v[indexA++]);elsetempVec.push_back(v[indexB++]);}// 将两个子表中还未遍历到的元素插入向量while (indexA < mid)tempVec.push_back(v[indexA++]);while (indexB < last)tempVec.push_back(v[indexB++]);// 操作完成, 临时向量当前有序, 将临时向量元素插入源向量中indexA = first;for (int i = 0; i < tempVec.size(); ++i)v[indexA++] = tempVec[i];}template <typename T>void mergeSort(vector<T>& v, int first, int last){if (first + 1 < last){//利用后跟遍历的方式, 将向量进行归并排序int mid = (first + last) / 2;mergeSort(v, first, mid);mergeSort(v, mid, last);merge(v, first, mid, last);}}/*    归并排序end*//*    快速排序begin*/template <typename T>int pivotIndex(vector<T>& v, int first, int last){// 记录中间位置int mid;// scanUp负责从开始搜索第一个大于基准的元素, scanDown负责从末尾开始第一个大于等于基准的元素int scanUp, scanDown;mid = (first + last) / 2;scanUp = first + 1;scanDown = last - 1;swap(v[mid], v[first]);// 找出基准为准位置while (true){// 从第一个元素开始找到第一个 > 基准的元素while (scanUp < last && v[scanUp] < v[first])scanUp++;// 从最后一个元素开始找到第一个小于等于基准的元素while (v[first] < v[scanDown])scanDown--;// 如果两个位置出现交叉, 跳出循环if (scanDown < scanUp)break;swap(v[scanDown--], v[scanUp++]);}if (scanDown != first)swap(v[scanDown], v[first]);return scanDown;}// sort a vector using quicksorttemplate <typename T>void quicksort(vector<T>& v, int first, int last){if (last - first <= 1)return;// 如果向量中少于等于一个元素一什么都不做else if (last - first == 2)// 如果向量中只有两个元素, 直接比较, 排序后返回{if (v[last - 1] < v[first])swap(v[first], v[last - 1]);return;}else{int pivot = pivotIndex(v, first, last);// 找到基准元素quicksort(v, first, pivot);// 对基准以前位置的元素进行排序quicksort(v, pivot + 1, last);// 对基准以后位置的元素进行排序}}/*    快速排序end*//*    基数排序begin*/int Power(const int limitNumber){int power = 1;// 判断当前处理的数字的位数int number = limitNumber;// 记录值的范围while (true){if ((number = number / 10) != 0)power++;elsebreak;}return power;}template <typename T>void distribute(vector<T>& v, queue<T> q[10], int power){// 遍历向量, 排序向量的排序power位for (int i = 0; i < v.size(); i++){q[v[i] / power % 10].push(v[i]);}}template <typename T>void collect(queue<T> q[10], vector<T>& v){// 记录向量下个访问的下标int index = 0;// 遍历排序的队列数组, 将元素返回向量for (int i = 0; i < 10; ++i){while (!q[i].empty()){v[index++] = q[i].front();q[i].pop();}}}template <typename T>void radixSort(vector<T>& v, const int limitNumber){int power = 1;queue<T> digitQueue[10];// 得到当前排序数字最高的位数int d = Power(limitNumber);// 逐位排序for (int i = 0; i < d; ++i){distribute(v, digitQueue, power);collect(digitQueue, v);power *= 10;}}/*    基数排序end*/template <typename T>void shellSort(vector<T>& v, const size_t first, const size_t last){if (v.empty() || first >= last) {throw invalid_argument("希尔排序参数错误!");}const size_t LENGTH = last - first;size_t gap = LENGTH;T temp;do {gap = gap / 3 + 1;// 内层循环是直接插入排序,只是各相邻排序元素间隔为 gap. for (int i = gap; i < LENGTH; i += gap){temp = v[i];int j;for ( j = i; j >= gap && temp < v[j - gap]; j -= gap){v[j] = v[j - gap];}if (j >= 0) {v[j] = temp;}}} while (gap > 1);}#endif // !SORT_FUNCTIONS


 

0 0
原创粉丝点击