因为笔者数据结构要考试了,所以在这里总结了一些用c语言实现的七大排序方法(均为升序实现),希望对于刚学数据结构与算法的同学能起到帮助。
一、冒泡排序
基本思路:
本质上是每两个数字之间的比较,每次比较后只需要把数字大的移动到后面即可,即每一次比较之后都会有现存数组中值最大的被移动到最后面,同时被固定住,在进行下次比较时,就不必再考虑。
代码实现
那么这里实现显然就需要两层循环,第一层循环的目的是控制选取的次数,即需要选取每次移动到最后的值的个数,故需要循环(n-1)次。第二层就是每次将基准值与后面的进行比较,一直将现存的值中最大的移动到后面,且固定住即可。
时间复杂度:O(n2)
稳定性:稳定 显然,当两个数值相同的时候,不会进行换序的操作的。
具体代码如下:
void BubbleSort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
return;
}
二、快速排序
基本思路:
先选取一个基准值(一般是数组的第一个元素),然后思路类似于折半查找,但是多一个赋值操作。从右端开始,如果比基准大就往左走,比基准值小就赋值给左端。对于左端还是一样的思路,最终再将基准值插入到左右指针相遇的位置即可。之后在继续切割成左右两端,进行相同的操作。
代码实现:
整体上的思路显然是进行递归操作。对于其中的一个子过程,可以先类比于二分查找,先设立low,high指针。一个从左边指,一个从右边指。将基准值用一个变量进行存贮。先从右边进行判断,如果比基准值大,就直接往左走,但是如果比基准值要小,就直接将这个值赋值给low所指的值,同时low往右移动,然后进入对low的操作,与high的操作相同,不再赘述。之后别忘了将基准值赋值给中间相遇点。之后,进行递归即可。
时间复杂度:O(nlogn)
稳定性:不稳定
具体代码如下:
void QuickSort(int a[], int low, int high) {
int i = low;
int j = high;
int t = a[i];
if (i >= j) {
return;
}
while (i < j) {
while (i<j&&a[j]>t) {
j--;
}
if (a[j] < t&& i < j)
{
a[i++] = a[j];
}
while (i < j&&a[i] < t)
{
i++;
}
if (a[i] > t && i < j) {
a[j--] = a[i];
}
}
a[i] = t;
QuickSort(a, low, i - 1);
QuickSort(a, i + 1, high);
}
三、堆排序
基本思路:
如果是想要最终进行升序排序,那么在进行调整的时候就要一直维持大根堆的形状。最后采用的是一种先确定后面,再确定前面的思路。即每次将大根堆的根节点与堆的最后一个节点交换,然后将最后一个值固定,再次进行adjust,重复操作即可。
代码实现:
需要两个函数,一个是用于做大根堆的调整,一个是用于进行堆排序的具体操作的。对于做大根堆的adjust函数,本质上就是判断每个根节点的左右字树的值是否大于根节点的值,若大于就将左右字树大的与根节点的值进行交换,若不大于就直接跳过。对于进行排序的函数来说,先要进行一些初始化,即从倒数第二层开始,先依次进行调整,这就是初始化(大家可以思考一下为什么)。然后就是依次将完全二叉树的根节点与最后一个节点进行交换即可,每次交换完进行大根堆的维持即可。
稳定性:不稳定
时间复杂度:O(nlogn)
void HeapAdjust(int a[],int v,int n) {
int i;
int t = a[v];
for (i = 2 * v + 1; i < n; i = 2 * i + 1) {
if (a[i + 1] > a[i]&&i+1<n) {
i++;
}
if (t > a[i])
break;
a[v] = a[i];
v = i;
}
a[v] = t;
return;
}
void HeapSort(int a[], int n) {
for (int i = n / 2-1; i >= 0; i--) {
HeapAdjust(a, i, n);
}
for (int j = n - 1; j >= 0; j--) {
int t = a[j];
a[j] = a[0];
a[0] = t;
HeapAdjust(a, 0, j);
}
return;
}
四、归并排序
基本思路:总体上就是字面意思,先拆开,最其中的小单元进行排序,然后逐渐整合,再对大单元进行逐层整合与排序,最终完成排序。
代码实现:由上述的解析可以看出,肯定是需要两个函数来进行操作。一个是微观的,对于有小到大的具体的排序过程的操作,就是设立两个指针,一个额外数组,一个从左端开始指,一个从中间开始指,找到一个小的就将其存入额外数组中,然后指针后移即可,最后如果一端到了尽头,就将剩下的未到尽头的一端全部赋值给额外数组即可。然后对于,总体来说,对于这种需要一直重复操作的思想肯定是递归。具体的参考代码即可,相信大家都是很容易理解的。
稳定性:稳定
时间复杂度:O(nlogn)
void merge(int a[], int left,int mid,int right, int t[]) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (a[i] < a[j]) {
t[k++] = a[i++];
}
else {
t[k++] = a[j++];
}
}
while (i <= mid) {
t[k++] = a[i++];
}
while (j <= right) {
t[k++] = a[j++];
}
memcpy(a + left, t + left, sizeof(int)*(right - left + 1));
return;
}
void MergeSort(int a[], int left,int right,int t[]) {
if (left >= right)
return;
int mid = (left + right) / 2;
MergeSort(a, left, mid,t);
MergeSort(a, mid + 1, right,t);
merge(a, left, mid, right, t);
}
五、简单插入排序
基本思路:
从第二个位置向数组的后面进行查找,如果发现有比后面的值大的,说明后面的值的位置出现了问题,于是需要再往前找,找到一个左右的值的大小都符合要求的位置,将其插入即可。
代码实现:
两个循环,第一个循环就是找不符合位置的值,并用一个变量将其存储起来,第二个循环就是从该值的前一个位置找起,将前一个值后移,等到找到一个与变量值相等或者小于变量值的位置后,跳出循环。那么该值的下一个位置就是你要插入的位置。
稳定性:稳定 因为在往前找的条件就是<=,当遇到我相等的值的时候,并不会改变顺序。
时间复杂度:O(n2)
void InsertSort(int a[], int n) {
int i, j;
for (i = 1; i <n; i++) {
if (a[i - 1] > a[i]) {
int t = a[i];
for (j = i - 1; j >= 0 && a[j]>t; j--) {
a[j + 1] = a[j];
}
a[j + 1] = t;
}
}
return;
}
六、简单选择排序
基本思路:
依次判断最小的是不是剩余数组的第一个元素,若是,将第一个元素固定住,往后面继续查找。若不是,就进行交换。
代码实现:
显然两层循环,两层循环是为了确定剩余数组中的最小值的位置,比较简单,不在赘述。然后就判断是否是剩余数组第一个元素的位置,不是就交换。
稳定性:不稳定 例如:53518,在进行第一次排序之后,两个5的顺序其实是会发生改变的。
时间复杂度:O(n2)
void SelectSort(int a[], int n) {
int v;
int i, j;
for (i = 0; i < n; i++) {
int v = i;
int min = a[i];
for (j = i + 1; j < n; j++) {
if (a[j] < min) {
v = j;
min = a[j];
}
}
if (v != i) {
int temp = a[i];
a[i] = a[v];
a[v] = temp;
}
}
return;
}
七、希尔排序
基本思想:
其实就是划分了多个GAP的插入排序,在每一个GAP组里面进行插排,然后不断减小GAP的值,到一为止,其实最后就是插排。
代码实现:与插排大部分类似,就是外面多了一层控制GAP的循环条件,然后里面对于移动到前一个位置的加减1全部换成加减GAP即可。
稳定性:不稳定 ,虽然插排是稳定的,但是对于划分了多个GAP的插排,他只是在每一个GAP里面符合稳定的特征而已,在每一个GAP组之间是不好判断的。
时间复杂度:经计算应该是O(n1.3)左右。
void ShellSort(int a[], int n) {
int gap, i, j, k;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = 0; i < gap; i++) {
for (j = i + gap; j < n; j+=gap) {
if (a[j - gap] > a[j]) {
int t = a[j];
for (k = j - gap; k >= 0 && a[k] > t; k-=gap) {
a[k + gap] = a[k];
}
a[k + gap] = t;
}
}
}
}
return;
}
以下是代码整体以及测试主函数(经测试代码正确)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//冒泡排序
void bubblesort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
return;
}
void BubbleSort(int a[], int n) {
bubblesort(a, n);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
}
//快速排序
void quicksort(int a[], int low, int high) {
int i = low;
int j = high;
int t = a[i];
if (i >= j) {
return;
}
while (i < j) {
while (i<j&&a[j]>t) {
j--;
}
if (a[j] < t&& i < j)
{
a[i++] = a[j];
}
while (i < j&&a[i] < t)
{
i++;
}
if (a[i] > t && i < j) {
a[j--] = a[i];
}
}
a[i] = t;
quicksort(a, low, i - 1);
quicksort(a, i + 1, high);
}
void QuickSort(int a[], int low,int n) {
quicksort(a, low, n-1);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
}
//堆排序
void HeapAdjust(int a[],int v,int n) {
int i;
int t = a[v];
for (i = 2 * v + 1; i < n; i = 2 * i + 1) {
if (a[i + 1] > a[i]&&i+1<n) {
i++;
}
if (t > a[i])
break;
a[v] = a[i];
v = i;
}
a[v] = t;
return;
}
void heapsort(int a[], int n) {
for (int i = n / 2-1; i >= 0; i--) {
HeapAdjust(a, i, n);
}
for (int j = n - 1; j >= 0; j--) {
int t = a[j];
a[j] = a[0];
a[0] = t;
HeapAdjust(a, 0, j);
}
return;
}
void HeapSort(int a[], int n) {
heapsort(a, n);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
}
//归并排序
void merge(int a[], int left,int mid,int right, int t[]) {
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (a[i] < a[j]) {
t[k++] = a[i++];
}
else {
t[k++] = a[j++];
}
}
while (i <= mid) {
t[k++] = a[i++];
}
while (j <= right) {
t[k++] = a[j++];
}
memcpy(a + left, t + left, sizeof(int)*(right - left + 1));
return;
}
void mergesort(int a[], int left,int right,int t[]) {
if (left >= right)
return;
int mid = (left + right) / 2;
mergesort(a, left, mid,t);
mergesort(a, mid + 1, right,t);
merge(a, left, mid, right, t);
}
void MergeSort(int a[], int left, int right, int t[]) {
mergesort(a, left, right, t);
for (int i = 0; i < right + 1; i++) {
printf("%d ", a[i]);
}
}
//插入排序
void insertsort(int a[], int n) {
int i, j;
for (i = 1; i <n; i++) {
if (a[i - 1] > a[i]) {
int t = a[i];
for (j = i - 1; j >= 0 && a[j]>t; j--) {
a[j + 1] = a[j];
}
a[j + 1] = t;
}
}
return;
}
void InsertSort(int a[], int n) {
insertsort(a, n);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
return;
}
//选择排序
void selectsort(int a[], int n) {
int v;
int i, j;
for (i = 0; i < n; i++) {
int v = i;
int min = a[i];
for (j = i + 1; j < n; j++) {
if (a[j] < min) {
v = j;
min = a[j];
}
}
if (v != i) {
int temp = a[i];
a[i] = a[v];
a[v] = temp;
}
}
return;
}
void SelectSort(int a[], int n) {
selectsort(a, n);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
}
//希尔排序
void shellsort(int a[], int n) {
int gap, i, j, k;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = 0; i < gap; i++) {
for (j = i + gap; j < n; j+=gap) {
if (a[j - gap] > a[j]) {
int t = a[j];
for (k = j - gap; k >= 0 && a[k] > t; k-=gap) {
a[k + gap] = a[k];
}
a[k + gap] = t;
}
}
}
}
return;
}
void ShellSort(int a[], int n) {
shellsort(a, n);
for (int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
}
int main() {
int a[10] = { 5,6,4,7,8,9,2,3,1,10 };
int n = 10;
int t[10];
//BubbleSort(a, n);
//QuickSort(a, 0, n);
//HeapSort(a, n);
//MergeSort(a, 0, n - 1, t);
//InsertSort(a, n);
//SelectSort(a, n);
//ShellSort(a, n);
system("pause");
return 0;
}
希望大家对于出现的错误在评论区进行探讨,谢谢大家!!!