十大经典排序算法

十大经典排序算法

参考网站

1.十大排序——最全最详细,一文让你彻底搞懂-CSDN博客

2.【十大经典排序算法(C语言描述)】https://www.bilibili.com/video/BV1nN4y1M7JK?p=6&vd_source=57dbe1b7ae720516dd577f4132a0370e

分类

1.交换类

1.冒泡排序(一个基于交换的数组,每一轮搜索这个序列的最大值,并将这个最大值放在序列的尾部)
  • 优化前
#include<stdio.h>`
#include<stdlib.h>
#include<time.h>
`//自定义数组最大长度`

`#define MAXSIZE 10`

`//取随机数`
`void initArr(int arr[], int length) {`
	`for (int i = 0; i < length;i++) {`
		`arr[i] = rand() % 20;//20以内的随机数`
	`}`
`}`

`//打印随机数`
`void showArr(int arr[],int length) {`
	`for (int i = 0; i < length; i++) {`
		`printf("%d  ", arr[i]);`
	`}`
	`printf("\n------------------------------------------------\n");`
`}`
`//给随机数排序`
`void bubSort(int arr[],int length) {`
	`while (length--) {`
		`for (int i = 0; i < length; i++) {`
			`if (arr[i] > arr[i + 1]) {`
				`int temp = arr[i];`
				`arr[i] = arr[i + 1];`
				`arr[i + 1] = temp;`
			`}`
		`}`
	`}`
`}`

`int main() {`
	`srand((unsigned int)time(NULL));//设置随机数种子,不然每次随机到的数都是一样的`
	`int arr[MAXSIZE];`
	`initArr(arr,MAXSIZE);`
	`showArr(arr,MAXSIZE);`
	`bubSort(arr,MAXSIZE);`
	`showArr(arr,MAXSIZE);`
	`return 0;`
`}`


  • 优化后(加入flag后,最大值和之前一样排到最后,但是之前的序列已经完成排序,就可以不用再进行循环)
    `#include<stdio.h>`
    `#include<stdlib.h>`
    `#include<time.h>`
    
    `//自定义数组最大长度`
    `#define MAXSIZE 10`
    
    `//取随机数`
    `void initArr(int arr[], int length) {`
    	`for (int i = 0; i < length;i++) {`
    		`arr[i] = rand() % 20;//20以内的随机数`
    	`}`
    `}`
    
    `//打印随机数`
    `void showArr(int arr[],int length) {`
    	`for (int i = 0; i < length; i++) {`
    		`printf("%d  ", arr[i]);`
    	`}`
    	`printf("\n------------------------------------------------\n");`
    `}`
    `//给随机数排序`
    `void bubSort(int arr[],int length) {`
    
         `int flag=1;`
    
    	`while (length--&&flag) {`
    
           `flag=0;`
    
    		`for (int i = 0; i < length; i++) {`
    
                `flag=1;`
    
    			`if (arr[i] > arr[i + 1]) {`
    				`int temp = arr[i];`
    				`arr[i] = arr[i + 1];`
    				`arr[i + 1] = temp;`
    			`}`
    		`}`
    	`}`
    `}`
    
    `int main() {`
    	`srand((unsigned int)time(NULL));//设置随机数种子,不然每次随机到的数都是一样的`
    	`int arr[MAXSIZE];`
    	`initArr(arr,MAXSIZE);`
    	`showArr(arr,MAXSIZE);`
    	`bubSort(arr,MAXSIZE);`
    	`showArr(arr,MAXSIZE);`
    	`return 0;`
    `}`
    
    
    
2.快速排序(冒泡排序的优化版本,核心思想:使用轴,每一轮左右递归后,把轴放在中间,使轴左边都比轴小,右边都比轴大,当所有的递归都结束以后就自然排好序了)
  • 优化前:不适用于单链表,只适用于顺序存储
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define MAXSIZE 10

//获取随机数
void initArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 100;
	}
}

//打印序列
void showArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n--------------------------------------\n");
}

//快速排序
void quickSort(int arr[],int left,int right) {
	if (left>=right) {return;}//函数出口
	int i = left;
	int j = right;
	int pviot = arr[i];//轴的初始值
	while(i<j){
	  while (i<j&&arr[j]>pviot) {
		  j--;
	  }//先从右往左找比轴大的值
	  arr[i] = arr[j];//找到以后j暂时代替轴的位置
	  while (i<j&&arr[i]<pviot) {
		  i++;
	  }//从左往右找比轴小的值
	  arr[j] = arr[i];//找到以后赋值给j的位置
	}
	arr[i] = pviot;
	quickSort(arr,left,i-1);//轴左边开始递归
	quickSort(arr,i+1,right);//轴右边开始递归
}


int main() {
	int arr[MAXSIZE];
	srand((unsigned)time(NULL));
	initArr(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	quickSort(arr,0,MAXSIZE-1);
	showArr(arr, MAXSIZE);
	return 0;
}
  • ;优化后:适用于链式存储

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define MAXSIZE 10
    
    //获取随机数
    void initArr(int arr[], int length) {
    	for (int i = 0; i < length; i++) {
    		arr[i] = rand() % 100;
    	}
    }
    
    //打印序列
    void showArr(int arr[], int length) {
    	for (int i = 0; i < length; i++) {
    		printf("%d ", arr[i]);
    	}
    	printf("\n--------------------------------------\n");
    }
    
    //交换
    void swap(arr[],int i,int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    
    //快速排序
    void quickSort(int arr[],int left,int right) {
    	if (left>=right) {return;}//函数出口,函数出口一般放在函数开头
    	int pviot = arr[left];//轴的初始值
        int i = left + 1;
    	int j = right + 1 ;
    	while(j<=right){
            if(arr[j]<pviot){
                swap(arr,i,j);
                i++;
            }
            j++;
        }
    	swap(arr,left,i-1);
    	quickSort(arr,left,i-2);//轴左边开始递归
    	quickSort(arr,i,right);//轴右边开始递归
    }
    
    
    int main() {
    	int arr[MAXSIZE];
    	srand((unsigned)time(NULL));
    	initArr(arr, MAXSIZE);
    	showArr(arr, MAXSIZE);
    	quickSort(arr,0,MAXSIZE-1);
    	showArr(arr, MAXSIZE);
    	return 0;
    }
    

2.分配类

1.计数排序(统计原来数组的数据,并将数据转换成下标存储在一个临时的空间中,然后变量临时空间把对应的下标值放回原数组,当遍历临时空间完成后,原来的数组就是排好序了)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

//打印序列
void showArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d  ", arr[i]);
	}
	printf("\n----------------------------------------\n");
}

void swap(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

int temp[100];//偷懒写法:临时数组
void countSort(int arr[],int length) {
	for (int i = 0; i < length;i++) {
		temp[arr[i]]++;//把arr[i]的数值当作temp的下标
	}
	for (int i = 0, j = 0; i < 100;i++) {
		while (temp[i]--) {
			arr[j++] = i;
		}
	}
}

int main() {
	int arr[MAXSIZE];
	srand((unsigned)time(NULL));
	initArr(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	countSort(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	return 0;
}
2.基数排序(统计序列数的最大位数,第一轮从100开始,第二轮从101开始,以此类推,统计每轮相应位数的最大值,并放在最前面,直到最后)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

//打印序列
void showArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d  ", arr[i]);
	}
	printf("\n----------------------------------------\n");
}

void swap(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

int temp[10][100];
void redixSort(int arr[],int length) {
	for (int k = 10; k < 10000;k*=10) {
		for (int i = 0; i < length;i++) {
			int j = 0;
			int pos = (arr[i] % k) / (k / 10);
			while (temp[pos][j]) {
				j++;
			}
			temp[pos][j] = arr[i];
		}
		int pos = 0;
		for (int i = 0; i < 10;i++) {
			for (int j = 0; j < length&& temp[i][j] != 0;j++) {
					arr[pos++] = temp[i][j];
					temp[i][j] = 0;
			}
		}
	}
}

int main() {
	int arr[MAXSIZE];
	srand((unsigned)time(NULL));
	initArr(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	redixSort(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	return 0;
}

3.选择类

1.选择排序(快速排序是在冒泡排序的基础上,每一轮找到序列中的最小值后和第一个元素进行交换,以此类推)
`#include<stdio.h>`

`#include<stdlib.h>`

`#include<time.h>`

`define MAXSIZE 10`

`//取随机数`
`void initArr(int arr[],int length) {`
	`for (int i = 0; i < length; i++) {`
		`arr[i] = rand() % 20;`
	`}`
`}`
`//打印随机数`
`void showArr(int arr[], int length) {`
	`for (int i = 0; i < length;i++) {`
		`printf("%d  ",arr[i]);`
	`}`
	`printf("\n----------------------------------------\n");`
`}`

`//给序列排序`
`void selectSort(int arr[],int length) {`
	`for (int i = 0; i < length - 1;i++) {`
		`int k = i;`
		`for (int j = i + 1; j < length;j++) {`
			`if(arr[k]>arr[j]) {`
				`k = j;`
			`}`
		`}`
		`int temp = arr[i];`
		`arr[i] = arr[k];`
		`arr[k] = temp;`
	`}`
`}`

`int main() {`
	`srand((unsigned int)time(NULL));`
	`int arr[MAXSIZE];`
	`initArr(arr, MAXSIZE);`
	`showArr(arr, MAXSIZE);`
	`selectSort(arr, MAXSIZE);`
	`showArr(arr, MAXSIZE);`
	`return 0;`
`}`
2.堆排序(本质上就是一个完全二叉树,每一个节点的存储都是连续的)
  • 大顶堆
    • 父亲的权值比左右子树的权值大
  • 小顶堆
    • 父亲的权值比左右子树的权值小

当前下标为current

  • 从0开始计数

    • 左子树–>2*current+1
    • 右子树–>2*current+2
  • 从1开始计数

    • 左子树–>2*current
    • 右子树–>2*current+1
  • 外堆

    • 需要一段和原来数组长度大小的内存空间,这段内存空间是用来存储堆结构的(用小顶堆)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

//打印序列
void showArr(int arr[], int length) {
	for (int i = 0; i < length; i++) {
		printf("%d  ", arr[i]);
	}
	printf("\n----------------------------------------\n");
}

void swap(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
//堆结构
typedef struct Heap {
	int* root;
	int length;
}Heap;

//入堆申请内存
Heap* creatHeap(int length) {
	Heap* heap = (Heap*)malloc(sizeof(Heap));
	assert(heap);
	heap->length = 0;
	heap->root = (int*)malloc(sizeof(int) * length);
	assert(heap->root);
	return heap;
}

//入堆
void pushHeap(Heap* heap,int data) {
	int current = heap->length++;
	int parent = current / 2;//求父亲下标
	heap->root[current] = data; 
	while (parent != current) {
		if (heap->root[current] < heap->root[parent]) {
			swap(heap->root, current, parent);
			current = parent;
			parent = current / 2;
		}
		else 
			break;
	}
}

//出堆
int popHeap(Heap* heap) {
	int val = heap->root[0];
	int current = 0;
	int rchild = 2 * current+2;
	int small;
	heap->root[0] = heap->root[--heap->length];
	while (rchild <= heap->length) {
		small = heap->root[rchild - 1] < heap->root[rchild] ? rchild - 1 : rchild;
		if (heap->root[small] < heap->root[current]) {
			swap(heap->root, small, current);
			current = small;
			rchild = 2 * current + 2;
		}
		else
			break;
	}
	return val;
}

//堆排序
void heapSort(int arr[],int length) {
	Heap* heap = creatHeap(MAXSIZE);
	for (int i = 0; i < MAXSIZE; i++) {
		pushHeap(heap, arr[i]);
	}
	for (int i = 0; i < MAXSIZE; i++) {
		arr[i] = popHeap(heap);
	}
}

int main() {
	int arr[MAXSIZE];
	srand((unsigned)time(NULL));
	initArr(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	heapSort(arr,MAXSIZE);
	showArr(arr, MAXSIZE);
	return 0;
}
  • 内堆
    • 不需要重新申请内存,直接在原来的数组上排序(用大顶堆)
void heapify(int arr[], int length, int current) {
	int rchild = 2 * current + 2;
	int large;
	while (rchild <= length) {
		large = rchild == length ? rchild - 1 : (arr[rchild - 1] > arr[rchild] ? rchild - 1 : rchild);
		if (arr[large] > arr[current]) {
			swap(arr, large, current);
			current = large;
			rchild = current * 2 + 2;
		}
		else
			break;
	}
}


//内堆
void heapSort2(int arr[], int length) {
	int current = length / 2;
	while (current >= 0) {
		heapify(arr, length, current);
		current--;
	}
	while (length) {
		swap(arr, 0, --length);
		heapify(arr, length, 0);
	}
}

4.归并类

归并排序(基于分而治之的思想,拿两个已经有序的序列重新组合成一个有序的新序列)
  • 优化前
#include<stdio.h>
#include<time.h>
#include<stdlib.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[],int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

//打印序列
void showArr(int arr[],int length) {
	for (int i = 0; i < length;i++) {
		printf("%d  ",arr[i]);
	}
	printf("\n----------------------------------------\n");
}

//归并排序
//默认a和b数组都是有序的
void mergeSort(int a[], int alen,int b[],int blen,int* temp) {
	int i = 0;//a下标初始化
	int j = 0;//b下标初始化
	int k = 0;//新数组下标初始化
	while (i < alen && j < blen) {
		if (a[i]<b[j]) {
			temp[k] = a[i];
			i++;
			k++;
		}
		else {
			temp[k] = b[j];
			j++;
			k++;
		}
	}
	while (i < alen) {
		temp[k] = a[i];
		i++;
		k++;
	}
	while (j < blen) {
		temp[k] = b[j];
		j++;
		k++;
	}
}

//手动输入序列
void scanfArr(int arr[]) {
	printf("Please add arr:");
	for (int i = 0; i < MAXSIZE;i++) {
		scanf_s("%d", &arr[i]);
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int arr1[5] = { 1,3,5,7,9 };//序列a
	int arr2[5] = { 2,4,6,8,10 };//序列b
	int temp[10];//新序列
	mergeSort(arr1, 5, arr2, 5, temp);
	showArr(temp,10);
	return 0;
}
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[],int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

//打印序列
void showArr(int arr[],int length) {
	for (int i = 0; i < length;i++) {
		printf("%d  ",arr[i]);
	}
	printf("\n----------------------------------------\n");
}

//归并
void merge(int arr[],int low,int mid,int height,int* temp) {
	int i = low;
	int j = mid + 1;
	int k = low;
	while (i<=mid&&j<=height) {
		temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
	}
	while (i <= mid) {
		temp[k++] = arr[i++];
	}
	while (j <= height) {
		temp[k++] = arr[j++];
	}
	//重新排列
	for (i = low; i <= height;i++) {
		arr[i] = temp[i];
	}
}

//划分序列
void merge_sort(int arr[],int low,int height,int* temp) {
	if (low>=height) {
		return;
	}
	int mid = low + (height - low) / 2;//求mid
	merge_sort(arr, low, mid, temp);//划分小的部分
	merge_sort(arr, mid+1, height, temp);//划分大的部分
	merge(arr, low, mid, height, temp);//合并序列
}

//最终归并的函数
void mergeSort(int arr[],int length) {
	int* temp = (int*)malloc(sizeof(int) * length);//申请空间
	assert(temp);
	merge_sort(arr, 0, length - 1, temp);
	free(temp);
}


int main() {
	int arr[MAXSIZE];
	srand((unsigned)time(NULL));
	initArr(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	mergeSort(arr,MAXSIZE);
	showArr(arr, MAXSIZE);
	return 0;
}

5.插入类

1.插入排序(优点是序列已经基本有序时,再将一个新的数据插入进来比较方便,效率较高)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define MAXSIZE 10

//随机获取序列
void initArr(int arr[],int length) {
	for (int i = 0; i < length; i++) {
		arr[i] = rand() % 20;
	}
}

void showArr(int arr[],int length) {
	for (int i = 0; i < length;i++) {
		printf("%d  ",arr[i]);
	}
	printf("\n----------------------------------------\n");
}

//插入排序
void insertSort(int arr[],int length) {
	for (int i = 1; i < length;i++) {
		for (int j = i; j > 0 && arr[j] < arr[j-1];j--) {
			int temp = arr[j];
			arr[j] = arr[j - 1];
			arr[j - 1] = temp;
		}
	}
}

//手动输入序列
void scanfArr(int arr[]) {
	printf("Please add arr:");
	for (int i = 0; i < MAXSIZE;i++) {
		scanf_s("%d", &arr[i]);
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int arr[MAXSIZE];
	srand((unsigned int)time(NULL));
	/*initArr(arr,MAXSIZE);
	showArr(arr, MAXSIZE);*/
	scanfArr(arr);
	insertSort(arr, MAXSIZE);
	showArr(arr, MAXSIZE);
	return 0;
}
2.希尔排序(优化版的插入排序,原数组很大的情况适用.如果插入排序步长是1,那么希尔排序步长可以更大,然后逐渐减小直到1形成插入排序)
  • 优化前(步数是自己定义的,需要自己计算)

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define MAXSIZE 1000
    
    //获取随机数
    void initArr(int arr[],int length) {
    	for (int i = 0; i < length;i++) {
    		arr[i] = rand() % 100;
    	}
    }
    
    //打印序列
    void showArr(int arr[], int length) {
    	for (int i = 0; i < length; i++) {
    		printf("%d ", arr[i]);
    	}
    	printf("\n--------------------------------------\n");
    }
    
    //希尔排序
    void shellSort(int arr[], int length) {
    	int h = 4;
    	while(h>=1)
    	{
    	  for (int i = h; i < length;i++) 
    	  {
    		 for (int j = i; j >= h && arr[j] < arr[j - 1];j-=h) 
    		 {
    			 int temp = arr[j];
    			 arr[j] = arr[j - h];
    			 arr[j - h] = temp;
    		 }
    	  }
    	  h /= 2;
        }
    }
    
    int main() {
    	int arr[MAXSIZE];
    	srand((unsigned)time(NULL));
    	initArr(arr, MAXSIZE);
    	showArr(arr, MAXSIZE);
    	shellSort(arr, MAXSIZE);
    	showArr(arr, MAXSIZE);
    	return 0;
    }
    
  • 优化后(步数是自动计算的,根据3*n+1来算需要的步数)

    理想的希尔排序序列为:1,4,10,…,3*n+1.

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define MAXSIZE 1000
    
    //获取随机数
    void initArr(int arr[],int length) {
    	for (int i = 0; i < length;i++) {
    		arr[i] = rand() % 100;
    	}
    }
    
    //打印序列
    void showArr(int arr[], int length) {
    	for (int i = 0; i < length; i++) {
    		printf("%d ", arr[i]);
    	}
    	printf("\n--------------------------------------\n");
    }
    
    //希尔排序
    void shellSort(int arr[], int length) {
    	int h = 1;//初始化h
    	int t = length / 3;//根据经典的希尔排序(3*n+1),来使其靠近这个数值
    	while (h < t) {
    		h = 3 * h + 1;//经典希尔排序序列,循环到最适合的h
    	}
    	while(h>=1)
    	{
    	  for (int i = h; i < length;i++) 
    	  {
    		 for (int j = i; j >= h && arr[j] < arr[j - 1];j-=h) 
    		 {
    			 int temp = arr[j];
    			 arr[j] = arr[j - h];
    			 arr[j - h] = temp;
    		 }
    	  }
    	  h /= 3;//前面有3*n,所以要除以3
        }
    }
    
    int main() {
    	int arr[MAXSIZE];
    	srand((unsigned)time(NULL));
    	initArr(arr, MAXSIZE);
    	showArr(arr, MAXSIZE);
    	shellSort(arr, MAXSIZE);
    	showArr(arr, MAXSIZE);
    	return 0;
    }
    
  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值