排序的算法有泡排序、选择排序、堆排序、插入排序、快排、归并排序和基数排序。
泡排序的基本思想是:将序列中的第一个元素与第二个元素进行比较,若前者大于后者则两者交换位置,否则不交换;依次类推直到n - 1个元素与第n个元素比较为止。经过如此一趟排序,使得n个元素中值最大的元素被安置在序列的第n个位置上。然后再对n - 1个元素进行相同的处理。
泡排序的代码如下:
void bubbleSort(vector<int> &nums) {
int n = nums.size();
bool change = false;
for (int i = 0;i < n; i++) {
change = false;
for (int j = 0;j < n - 1 - i;j++) {
if (nums[j] > nums[j + 1]) {
swap(nums[j], nums[j + 1]);
change = true;
}
}
if (!change) {
break;
}
}
return;
}
选择排序的的基本思想是第i趟排序从序列后n - i + 1个元素选一个值最小的元素和该n - i + 1个元素的最前面那个元素交换位置。
选择排序的代码如下:
void selectSort(vector<int> &nums) {
int n = nums.size();
for (int i = 0;i < n ;i++) {
int tmp = nums[i];
int tmpk = i;
for (int j = i + 1;j < n;j++) {
if (nums[j] < tmp) {
tmpk = j;
tmp = nums[j];
}
}
if (tmpk != i) {
swap(nums[i],nums[tmpk]);
}
}
}
插入排序的基本思想是第i趟排序将序列中的第i+1个元素插入到已经按值有序排列的序列中。插入排序的代码如下:
void insertSort(vector<int> &nums) {
int n = nums.size();
for (int i = 0;i < n;i++) {
int tmp = nums[i + 1];
int j = i;
while (j >= 0 && nums[j] > tmp) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = tmp;
}
}
快排是比较经典的一种排序算法,快排的核心思想是:在当前参加ks, ks + 1, … kt中任选一个元素,把小于分界元素的所有元素都移到分界元素的前面,大于等于分界元素的元素都移到分界元素的后面,这样分界元素就在最终位置上而且把数组分成两部分,这样就等于缩小了我们要处理的数组的规模。快排的代码如下:
void quickSort(vector<int> &nums, int start, int last) {
int i, j;
if (start < last) {
i = start;
j = last + 1;
while (true) {
do {
i++;
}while(i < last && nums[i] < nums[start]);
do {
j--;
}while(j >start && nums[j] > nums[start]);
if (i < j) {
swap(nums[i], nums[j]);
}
else {
break;
}
}
swap(nums[start], nums[j]);
quickSort(nums, start, j - 1);
quickSort(nums, j + 1, last);
}
}
堆是一种数据结构,堆是一颗完全二叉树,其中每个分支节点的值均大于或者等于其左子树或者右子树中所有节点的值,并且该完全二叉树的根节点值最大。如果用数组存储堆,那么对于根节点是i的子树,她的左子树的根节点是2*i,右子树的根节点是2*i+1。
堆排序的代码如下:
void adjust(vector<int> &nums, int root, int last) {
int j = 2 * root;
int tmp = nums[root];
while (j <= last) {
if (j < last && nums[j] < nums[j + 1]) {
j = j + 1;
}
if (tmp < nums[j]) {
nums[j / 2] = nums[j];
j = j * 2;
}
else {
break;
}
}
nums[j / 2] = tmp;
}
void heapSort(vector<int> &nums) {
int n = nums.size();
//堆排在构建堆的过程中比较复杂,但是这里利用从底向上的方法一点点构建出第一个大顶堆很机智
for (int i = (n - 1) / 2;i >= 0;i--) {
adjust(nums,i,n - 1);
}
for (int i = n - 2; i >= 0;i--) {
swap(nums[0],nums[i + 1]);
adjust(nums,0,i);
}
}
归并排序是指把两个有序的数组归并成一个有序的数组代码如下:
void merge(int s,int m,int e){
vector<int> tnum;
int ss=s;
int ms=m+1;
int k=0;
while(ss<=m&&ms<=e){
if(nums[ss]<nums[ms])
tnum.push_back(nums[ss++]);
else
tnum.push_back(nums[ms++]);
}
while(ss<=m)
tnum.push_back(nums[ss++]);
while(ms<=e)
tnum.push_back(nums[ms++]);
for(k=0;k<tnum.size();k++){
nums[s+k]=tnum[k];
}
}
void mergesort(int start,int end){
if(start<end){
int mid=(start+end)/2;
mergesort(start,mid);
mergesort(mid+1,end);
merge(start,mid,end);
}
}
基数排序,这是一个比较稳定的排序方法,但是也比较难理解。就是把数字按位从小到大进行排序。有一个比较详细的视频:https://www.youtube.com/watch?v=xhr26ia4k38
代码如下:
#include <iostream>
using namespace std;
int getMaxCount(int *A, int n) {
int max = A[0];
int count = 1;
for(int i= 1;i<n;i++) {
if(A[i]>max) {
max = A[i];
}
}
while(max/10 > 0) {
count++;
max /= 10;
}
return count;
}
int getValueAt(int val, int pos) {
while(--pos) {
val /= 10;
}
return val % 10;
}
int *radixSort(int *A, int n) {
int bucket[10] = {0};
int cnt = getMaxCount(A, n);
int index;
int *temp = new int[n];
for (int k = 1;k <= cnt;k++) {
for(int i = 0;i < 10;i++) {
bucket[i] = 0;
}
for (int i = 0;i < n;i++) {
index = getValueAt(A[i], k);
bucket[index]++;
}
for(int i = 1;i < 10;i++) {
bucket[i] += bucket[i - 1];
}
for(int i = n - 1;i >= 0;i--) {
int pos = --bucket[getValueAt(A[i], k)];
temp[pos] = A[i];
}
for(int i = 0;i < n;i++) {
A[i] = temp[i];
}
}
delete[] temp;
return A;
}
int main() {
int A[10] = {9, 128, 129,34,10,3,56,45,19,2};
int *B = radixSort(A, 10);
for(int i = 0;i < 10;i++) {
cout << B[i] << " ";
}
}