选择排序
指针表示法
void choose_sort(int* arr, int n) {
for (int i = 0; i < n; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (*(arr + j) < *(arr + minIndex)) {
minIndex = j;
}
}
swap(arr, minIndex, i);
}
}
数组表示法
void selectionSort(int arr[],int n){
for(int i=0;i<n;i++){
int minIndex = i;
for(int j=i+1;j<n;j++){
if(arr[j] < arr[minIndex]){
minIndex = j;
}
}
swap(arr,i,minIndex);
}
}
冒泡排序
void bubbleSort(int* arr,int n){
for(int i=n-1;i>0;i--){
for(int j=0;j<i;j++){
if(arr[j] > arr[j+1]){
swap(arr,j,j+1);
}
}
}
}
模板(泛型)
template <typename T>
void selectionSort(T arr[],int n){
for(int i=0;i<n;i++){
int minIndex = i;
for(int j=i+1;j<n;j++){
if(arr[j] < arr[minIndex]){
minIndex = j;
}
}
swap(arr,i,minIndex);
}
}
甚至可以对自定义类型进行排序,如定义结构体:
struct Student {
string name;
int score;
重载 < 号,为了自定义排序。
bool operator<(const Student& otherStudent) {
return score < otherStudent.score;
}
重载 << 输出,cout直接输出student结构体类型。
friend ostream& operator<<(ostream& os, const Student& student) {
os << "student:" << student.name << " " << student.score << endl
return os;
}
};
随机生成算法
<ctime> <cassert> <iostream>
assert 如果出现错误则中止,需要头文件包含 <cassert>
int* generateRandomArray(int n, int rangeL, int rangeR) {
assert(rangeL <= rangeR);
int* arr = (int*)malloc(sizeof(int) * n);
srand((unsigned)time(NULL));
for (int i = 0; i < n; i++) {
*(arr + i) = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
插入排序
普通的插入排序,只是交换。
void insertSort(int* arr,int n){
for(int i=1;i<n;i++){
for(int j=i;j>0;j--){
if(arr[j] < arr[j-1]){
swap(arr,j,j-1);
}
}
}
}
加强插入排序,仅仅当arr[j-1] 比 arr[j] 大的时候才修改 ,交换改成赋值。
设定一个temp为 arr[i],如果arr[j-1] 比 temp大,就说明该进行插入排序,直到后退到该放置temp的位置,然后内循环结束,在arr[j]处放置 temp。
void insertSort(int* arr,int n){
for(int i=1;i<n;i++){
int temp = arr[i];
int j;
for(j=i;j>0 && arr[j-1] > temp;j--){
arr[j] = arr[j-1];
}
arr[j] = temp;
}
}
迄今为止,学了三种基础排序,插入排序可以进行优化。
冒泡排序最慢、选择排序次之、插入排序再次之。(在一个基本有序的数列中,插入排序的速度有时比O(NlogN)的排序算法还快。
归并排序
void mergeSort(int* arr,int n);
void process(int* arr,int L,int R);
void merge(int* arr,int L,int mid,int R);
void mergeSort(int* arr,int n){
process(arr,0,n-1);
}
void process(int* arr,int L,int R){
if(L >= R){
return;
}
int mid = L + ((R-L)>>1);
process(arr,L,mid);
process(arr,mid+1,R);
merge(arr,L,mid,R);
}
void merge(int* arr,int L,int mid,int R){
int size = R-L+1;
新建数组
int* temp = (int*)malloc(sizeof(int)*size);
int p1 = L;
int p2 = mid+1;
int i = 0;
while(p1 <= L && p2 <= R){
temp[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while(p1 <= mid){
temp[i++] = arr[p1++];
}
while(p2 <= R){
temp[i++] = arr[p2++];
}
for(i=0;i<size;i++){
arr[L+i] = temp[i];
}
}
快速排序
// 快速排序
int partition(int* arr, int L, int R);
void quick(int* arr, int L, int R);
void quickSort(int* arr,int n);
void quickSort(int* arr, int n) {
quick(arr, 0, n - 1);
return;
}
int partition(int* arr, int L, int R) {
// 设置基准
int temp = arr[L];
int front = L;
for (int rear = L + 1; rear <= R; rear++) {
if (arr[rear] < temp) {
swap(arr, rear, ++front);
}
}
swap(arr, L, front);
return front;
}
void quick(int* arr, int L, int R) {
if (L >= R) {
return;
}
int p = partition(arr, L, R);
quick(arr, L, p - 1);
quick(arr, p + 1, R);
}
小结:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 5000000
void swap(int* arr, int i, int j) {
int temp = *(arr + i);
*(arr + i) = *(arr + j);
*(arr + j) = temp;
}
// 快速排序
int partition(int* arr, int L, int R);
void quick(int* arr, int L, int R);
void quickSort(int* arr, int n) { quick(arr, 0, n - 1); }
int partition(int* arr, int L, int R) {
// 设置基准
int temp = arr[L];
int front = L;
for (int rear = L + 1; rear <= R; rear++) {
if (arr[rear] < temp) {
swap(arr, rear, ++front);
}
}
swap(arr, L, front);
return front;
}
void quick(int* arr, int L, int R) {
if (L >= R) {
return;
}
int p = partition(arr, L, R);
quick(arr, L, p - 1);
quick(arr, p + 1, R);
}
// 交换
void insertSort(int* arr, int n) {
for (int i = 1; i < n; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
}
}
}
}
// 赋值代替交换
void insertSortPro(int* arr, int n) {
for (int i = 1; i < n; i++) {
int e = arr[i]; // 临时保存
int j; // 保存元素e应该插入的位置
for (j = i; j > 0 && arr[j - 1] > e; j--) {
arr[j] = arr[j - 1];
}
arr[j] = e;
}
}
// 选择排序
void selectionSort(int* arr, int n) {
for (int i = 0; i < n; i++) {
int minIndex = i;
for (int j = 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
swap(arr, i, minIndex);
}
}
// 冒泡排序
void bubbleSort(int* arr, int n) {
for (int i = n - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}
// 复制数组
int* copyIntArray(int* arr, int n) {
int* newArr = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
*(newArr + i) = *(arr + i);
}
return newArr;
}
// 打印数组
void print(int* arr, int n) {
for (int i = 0; i < n; i++) {
if (i % 10 == 0) {
printf("\n");
}
printf("%d\t", *(arr + i));
}
printf("\n");
}
// 按照长度和范围随机构建数组
int* getArr(int size, int randL, int randR) {
srand((unsigned)time(NULL));
int* arr = (int*)malloc(sizeof(int) * size);
for (int i = 0; i < size; i++) {
*(arr + i) = rand() % (randR - randL + 1) + randL;
}
return arr;
}
void merge(int* arr, int L, int mid, int R);
void process(int* arr, int L, int R);
void mergeSort(int* arr, int n) {
process(arr, 0, n - 1);
return;
}
void process(int* arr, int L, int R) {
if (L >= R) {
return;
}
int mid = L + ((R - L) >> 1);
process(arr, L, mid);
process(arr, mid + 1, R);
merge(arr, L, mid, R);
}
void merge(int* arr, int L, int mid, int R) {
// 创建一个 (R-L+1) 长度的数组
int size = R - L + 1;
int* newArr = (int*)malloc(sizeof(int) * size);
for (int i = L; i <= R; i++) {
newArr[i - L] = arr[i];
}
// 开始排序
int front = L;
int rear = mid + 1;
int i = 0;
while (front <= mid && rear <= R) {
newArr[i++] = arr[front] < arr[rear] ? arr[front++] : arr[rear++];
}
while (front <= mid) {
newArr[i++] = arr[front++];
}
while (rear <= R) {
newArr[i++] = arr[rear++];
}
for (i = 0; i < size; i++) {
arr[i + L] = newArr[i];
}
}
int* generateNearlyOrderedArray(int n, int count) {
srand((unsigned)time(NULL));
int* arr = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
for (int j = 0; j < count; j++) {
int p1 = rand() % n;
int p2 = rand() % n;
swap(arr, p1, p2);
}
return arr;
}
void test01() {
clock_t begin;
clock_t end;
double time;
int* arr1 = getArr(N, 0, N);
int* arr2 = copyIntArray(arr1, N);
int* arr3 = copyIntArray(arr1, N);
int* arr4 = copyIntArray(arr1, N);
int* arr5 = copyIntArray(arr1, N);
// 计算归并排序时间
printf("\n");
begin = clock();
mergeSort(arr5, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("mergeSort:\t%10lf s\n", time);
// 计算插入排序(落后)时间
begin = clock();
insertSort(arr1, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("insertSort:\t%10lf s\n", time);
// 计算插入排序(改进)时间
begin = clock();
insertSortPro(arr2, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("insertSortPro:\t%10lf s\n", time);
// 计算选择排序时间
begin = clock();
selectionSort(arr3, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("selectionSort:\t%10lf s\n", time);
// 计算冒泡排序时间
begin = clock();
bubbleSort(arr4, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("bubbleSort:\t%10lf s\n", time);
printf("\n");
free(arr1);
free(arr2);
free(arr3);
free(arr4);
free(arr5);
arr1 = NULL;
arr2 = NULL;
arr3 = NULL;
arr4 = NULL;
arr5 = NULL;
}
void test02() {
clock_t begin;
clock_t end;
double time;
int* arr1 = generateNearlyOrderedArray(N, 2);
int* arr2 = copyIntArray(arr1, N);
int* arr3 = copyIntArray(arr1, N);
int* arr4 = copyIntArray(arr1, N);
int* arr5 = copyIntArray(arr1, N);
// 计算归并排序时间
printf("\n");
begin = clock();
mergeSort(arr5, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("mergeSort:\t%10lf s\n", time);
// 计算插入排序(落后)时间
begin = clock();
insertSort(arr1, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("insertSort:\t%10lf s\n", time);
// 计算插入排序(改进)时间
begin = clock();
insertSortPro(arr2, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("insertSortPro:\t%10lf s\n", time);
// 计算选择排序时间
begin = clock();
selectionSort(arr3, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("selectionSort:\t%10lf s\n", time);
// 计算冒泡排序时间
begin = clock();
bubbleSort(arr4, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("bubbleSort:\t%10lf s\n", time);
printf("\n");
free(arr1);
free(arr2);
free(arr3);
free(arr4);
free(arr5);
arr1 = NULL;
arr2 = NULL;
arr3 = NULL;
arr4 = NULL;
arr5 = NULL;
}
int main() {
clock_t begin;
clock_t end;
double time;
int* arr1 = getArr(N, 0, N);
int* arr2 = copyIntArray(arr1, N);
// 计算归并排序时间
printf("\n");
begin = clock();
mergeSort(arr1, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("mergeSort:\t%10lf s\n", time);
// 计算快速排序时间
begin = clock();
quickSort(arr2, N);
end = clock();
time = end - begin;
time = time / CLOCKS_PER_SEC;
printf("quickSort:\t%10lf s\n", time);
printf("\n");
free(arr1);
free(arr2);
arr1 = NULL;
arr2 = NULL;
}
总结
快速排序大部分情况比归并排序还要快,在数组基本有序的情况下,优化过的插入排序比归并排序都要快。基础排序冒泡、选择都是非常慢的,O(N^2)级别的时间复杂度。
快速排序和归并排序是O(N logN)级别的。