这里可以附上一个模拟排序算法的网址 http://www.atool9.com/sort.php
一.交换排序
1.冒泡排序
/*
* 它重复地走访过要排序的数列,
* 一次比较两个元素,如果他们的顺序错误就把他们交换过来。
* 走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
*/
public:
static void bubbleSort(int array[], int length) {
for (int i = 0; i < length - 1; i++) { //确定排序次数
for (int j = 0; j < length - i - 1; j++) { //确定比较次数
if (array[j] > array[j + 1]) {
int temp = array[j + 1]; //交换
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
(1)冒泡排序优化
/*
* 假设我们现在排序ar[]={1,2,3,4,5,6,7,8,10,9}这组数据,
* 按照上面的排序方式,第一趟排序后将10和9交换已经有序,接下来的8趟排序就是多余的,什么也没做。
* 所以我们可以在交换的地方加一个标记,
* 如果那一趟排序没有交换元素,说明这组数据已经有序,不用再继续下去。
*/
public:
static void bubbleSort_1(int array[], int length) {
for (int i = 0; i < length - 1; i++) { //确定排序次数
bool hasSwaped = false;
for (int j = 0; j < length - i - 1; j++) {//确定比较次数
if (array[j] > array[j + 1]) {
int temp = array[j]; //交换
array[j] = array[j + 1];
array[j + 1] = key;
hasSwaped = temp; //标记已交换
}
}
if (!hasSwaped) { //如果没有发生过交换,则已经有序
break;
}
}
}
(2)冒泡排序优化
/*
* 我们可以记下最后一次交换的位置,
* 后边没有交换,必然是有序的,
* 然后下一次排序从第一个比较到上次记录的位置结束即可。
*/
public:
static void bubbleSort_2(int array[], int length) {
int k = length - 1;
for (int i = 0; i < length - 1; i++) {
int lastIndex = 0; //用来记录最后一次交换的位置
bool hasSwaped = false;
for (int j = 0; j < k; j++) { //确定排序次数
if (array[j] > array[j + 1]) { //确定排序次数
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
lastIndex = j; //交换元素,记录最后一次交换的位置
hasSwaped = true; //标记已交换
}
}
if (!hasSwaped) {
break;
}
k = lastIndex; //下一次比较上一次最后交换的位置即可
}
}
2.快速排序
/*
* 快速排序(Quicksort)是对冒泡排序的一种改进。
* 它的基本思想是:
* 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有 数据都要小,
* 然后再按此方法对这两部分数据分别进行快速排序,
* 整个排序过程可以递归进行,以此达到整个数据变成有序序列。
*/
public:
static void quickSort(int array[], int length) { //使封装更加易用
doQuick(array, 0, length - 1);
}
//递归
public:
static void doQuick(int array[], int left, int right) {
int par = partion(array, left, right);
if (left >= right) { //递归出口
return;
} else {
doQuick(array, left, right - 1); //对前半段进行快速排序
doQuick(array, left + 1, right); //对后半段进行快速排序
}
}
//返回基准位置
public:
static int partion(int array[], int left, int right) {
int key = array[left]; //默认取第一个元素作为基准元
while (left < right) {
while (left < right && array[right] >= key) {
right--;
}
array[left] = array[right];
while (left < right && array[left] <= key) {
left++;
}
array[right] = array[left];
}
array[left] = key; //基准元居中
return left;
}
(1)快速排序(非递归)
其中的partion()函数还是上面的,且需要引入头文件 stack
/*
* 递归的算法主要是在划分子区间,如果要非递归实现快排,只要使用一个栈来保存区间就可以了。
* 一般将递归程序改成非递归首先想到的就是使用栈,因为递归本身就是一个压栈的过程。
*/
public:
static void quickSort1(int array[], int length) {
stack<int> stack;
stack.push(0);
stack.push(length - 1); //后入的right端点,所以要先拿right
while (!stack.empty()) {
int right = stack.top(); //right端点在栈顶
stack.pop();
int left = stack.top();
stack.pop();
int index = partion(array, left, right);
if (index - 1 > left) { //左子序列
stack.push(left);
stack.push(index - 1);
}
if (index + 1 < right) { //右子序列
stack.push(index + 1);
stack.push(right);
}
}
}
二.插入排序
1.直接插入排序
/*
* 插入排序的基本思想是:
* 每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入 完为止。
*/
public:
static void insertSort(int array[], int length) {
for (int i = 0; i < length; i++) {
if (array[i] < array[i - 1]) {
int temp = array[i];
int j = 0;
for (int j = i - 1; j >= 0 && temp < array[j]; j--) {
array[j + 1] = array[j];
}
array[j + 1] = temp;
}
}
}
三.选择排序
1.简单选择排序
/*
* 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,
* 存放在序列的起始位置,直到全部待排序的数据元素排完。
* 选择排序是不稳定的排序方法。
*/
public:
static void selectSort(int array[], int length) {
for (int i = 0; i < length; i++) {
int index = i;
for (int j = i + 1; j < length; j++) {
if (array[j] < array[index]) {
index = j;
}
}
if (index != i) {
int temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}
}
四.归并排序
/*
* 归并排序是建立在归并操作上的一种有效的排序算法,
* 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
* 将已有序的子序列合并,得到完全有序的序列;
* 即先使每个子序列有序,再使子序列段间有序。
* 若将两个有序表合并成一个有序表,称为二路归并。
*/
public:
static void mergeSort(int array[], int length) {
int* temp = new int[length];
mergeSort(array, 0,length - 1, temp);
}
public:
static void mergeSort(int array[], int left, int right, int temp[]) {
if(left < right) {
int mid = (left + right) / 2;
mergeSort(array, left, mid, temp); //对左子数组进行归并排序
mergeSort(array, mid + 1, right, temp); //对右子数组进行归并排序
merge(array, left, mid, right, temp); //将数组进行排序
}
}
public:
static void merge(int array[], int left, int mid, int right, int temp[]) {
int i = left;
int j = mid + 1;
int t = 0; //辅助数组的下标
while (i <= mid && j <= right) {
//当二者都没有到达最后一位时,进行比较并向辅助数组复制
if (array[i] < array[j]) {
temp[t++] = array[i++];
} else {
temp[t++] = array[j++];
}
}
//当其中一个数组复制完毕后,将另一个数组内的数组全部复制到辅助辅助
while (i <= mid) {
temp[t++] = array[i++];
}
while (j <= right) {
temp[t++] = array[j++];
}
t = 0;
while (left <= right) {
array[left++] = temp[t++];
}
}
五.基数排序
这里用到了vector来模拟二维数组,需要引入头文件vector
/*
* 基数排序(Radix Sort)是桶排序的扩展。
* 它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
* 具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
* 然后,从最低位开始,依次进行一次排序。
* 这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
*/
//辅助函数, 求数据的最大位数
public:
static int maxBit(int array[], int length) {
int maxBit = 0;
for (int i = 0; i < length; i++) {
int bit = 1;
int temp = array[i];
while (temp / 10 != 0) { //计算每个数的位数存在count中
temp = temp / 10;
bit++;
}
maxBit = (bit > maxBit) ? bit : maxBit; //将最大数复制给maxBit;
}
return maxBit;
}
public:
static void radixSort(int array[], int length) {
int bit = maxBit(array, length); //取得最大位数
int radix = 1;
for (int i = 0; i < bit; i++) { //位数决定排序循环次数
int count[10]; //计数器count为了统计每个桶放了几个数
for (int j = 0; j < 10; j++) { //每次初始化计数器
count[j] = 0;
}
//这里用到vector来模拟二维数组
vector<vector<int>> temp; //temp相当于桶,前一个数标记第几个篮子,后一个为了标记放的个数
for (int j = 0; j < 10; j++) { //每次都初始化桶
vector<int> temp2(length, 10);
temp.push_back(temp2);
}
for (int j = 0; j < length; j++) {
int k = (array[j] / radix) % 10;
temp[k][count[k]] = array[j]; //把数据放k桶的te位上存储
count[k]++;
}
int b = 0;
for (int j = 0; j < 10; j++) {
if (count[j] > 0) { //j>0说明j桶内有数字存储
for (int k = 0; k < count[j]; k++) { //count[j]是j桶的存储个数
array[b] = temp[j][k]; //把桶内排好的数全都倒给要排序的数组,进行下轮排序
b++;
}
}
}
radix = radix * 10;
}
}
这里附上一个基数排序过程图解 https://www.cnblogs.com/skywang12345/p/3603669.html