常用七大排序算法总结(C语言描述)

目录

  其中排序算法总结如下:

一.交换排序

  交换排序的基本思想都为通过比较两个数的大小,当满足某些条件时对它进行交换从而达到排序的目的。

1.冒泡排序

  基本思想:比较相邻的两个数,如果前者比后者大,则进行交换。每一轮排序结束,选出一个未排序中最大的数放到数组后面。

#include<stdio.h>
//冒泡排序算法
void bubbleSort(int *arr, int n) {
    for (int i = 0; i<n - 1; i++)
        for (int j = 0; j < n - i - 1; j++)
        {
            //如果前面的数比后面大,进行交换
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
            }
        }
}
int main() {
    int arr[] = { 10,6,5,2,3,8,7,4,9,1 };
    int n = sizeof(arr) / sizeof(int);
    bubbleSort(arr, n);
    printf("排序后的数组为:\n");
    for (int j = 0; j<n; j++)
        printf("%d ", arr[j]);
    printf("\n");
    return 0;

分析:

  最差时间复杂度为O(n^2),平均时间复杂度为O(n^2)。稳定性:稳定。辅助空间O(1)。

  升级版冒泡排序法:通过从低到高选出最大的数放到后面,再从高到低选出最小的数放到前面,如此反复,直到左边界和右边界重合。当数组中有已排序好的数时,这种排序比传统冒泡排序性能稍好。

#include<stdio.h>
//升级版冒泡排序算法
void bubbleSort_1(int *arr, int n) {
    //设置数组左右边界
    int left = 0, right = n - 1;
    //当左右边界未重合时,进行排序
    while (left<right) {
        //从左到右遍历选出最大的数放到数组右边
        for (int i =left; i < right; i++)
        {
            if (arr[i] > arr[i + 1])
            {
                int temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = temp;
            }
        }
        right--;
        //从右到左遍历选出最小的数放到数组左边
        for (int j = right;j> left; j--)
        {
            if (arr[j + 1] < arr[j])
            {
                int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;
            }
        }
        left++;
    }

}
int main() {
    int arr[] = { 10,6,5,2,3,8,7,4,9,1 };
    int n = sizeof(arr) / sizeof(int);
    bubbleSort_1(arr, n);
    printf("排序后的数组为:\n");
    for (int j = 0; j<n; j++)
        printf("%d ", arr[j]);
    printf("\n");
    return 0;
}

  

2.快速排序

  基本思想:选取一个基准元素,通常为数组第一个元素。通过从后向前遍历和从前向后遍历数组,把数组元素和基准元素进行比较,把数组分成两份,一份比基准元素大,一份比基准元素小。在利用分治策略从已经分好的两组中分别进行以上步骤,直到排序完成。

  

#include<stdio.h>
void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}
//划分函数,将数组划分为两份,一份比基准元素小,一份比基准元素大
int partition(int *arr, int left, int right) {

    int key = arr[left];    //选取第一个元素为基准元素
    while (left < right) {

        while ( left < right && arr[right]>= key )    //从后向前遍历
                --right;
            swap(&arr[left], &arr[right]);    //当后面的数字小于基准元素时,交换左右当前位

        while (left < right && arr[left] <= key)    //从前向后遍历
                ++left;
            swap(&arr[left], &arr[right]);    //当前面的数字大于基准元素时,交换左右当前位

    }
    return left;    //返回基准索引
}
void quickSort(int * arr, int left,int right) {
    if (left >= right)
        return;
    int mid = partition(arr, left, right);
    quickSort( arr,  left, mid - 1);
    quickSort( arr, mid + 1, right);

}
int main() {
    int arr[] = { 10,6,5,2,3,8,7,4,9,1 };
    int n = sizeof(arr) / sizeof(int);
    quickSort(arr, 0, n-1);
    printf("排序后的数组为:\n");
    for (int j = 0; j<n; j++)
        printf("%d ", arr[j]);
    printf("\n");
    return 0;
}

分析:  

  最差时间复杂度:每次选取的基准元素都为最大(或最小元素)导致每次只划分了一个分区,需要进行n-1次划分才能结束递归,故复杂度为O(n^2);最优时间复杂度:每次选取的基准元素都是中位数,是的每次都划分出两个分区,需要进行logn次递归,故时间复杂度为O(nlogn);平均时间复杂度:O(nlogn)。稳定性:不稳定的。辅助空间:O(nlogn)。

  当数组元素基本有序时,快速排序将没有任何优势,基本退化为冒泡排序,可在选取基准元素时选取中间值进行优化。

二.插入排序

  

1.直接插入排序

  基本思想:和交换排序不同的是它不用进行交换操作,而是用一个临时变量存储当前值。当前面的元素比后面大时,先把后面的元素存入临时变量,前面元素的值放到后面元素位置,再到最后把其值插入到合适的数组位置。      

#include<stdio.h>
void InsertSort(int  *a, int n) {
    int tmp = 0;
    for (int i = 1; i < n; i++) {
        int j = i - 1;
        if (a[i] < a[j]) {
            tmp = a[i];
            a[i] = a[j];
            while (tmp < a[j-1]) {
                a[j] = a[j-1];
                j--;
            }
            a[j] = tmp;
        }
    }
}
int main() {
    int a[] = { 11,7,9,22,10,18,4,43,5,1,32};
    int n = sizeof(a)/sizeof(int);
    InsertSort(a, n);
    printf("排序好的数组为:");
    for (int i = 0; i < n; i++) {
        printf(" %d", a[i]);
    }
    printf("\n");
    return 0;
}

 分析

  最坏时间复杂度为数组为逆序时,为O(n^2)。最优时间复杂度为数组正序时,为O(n)。平均时间复杂度为O(n^2)。辅助空间O(1)。稳定性:稳定。

2.希尔(shell)排序

  基本思想为在直接俄插入排序色思想下设置一个最小增量dk,刚开始dk设置为n/2。当猴进行插入排序,随后再让dk=dk/2,再进行插入排序,直到dk为1时完成最后一次插入排序,此时数组完成排序。

#include<stdio.h>
//    进行插入排序
//    初始时从dk开始增长,每次比较步长为dk
void Insrtsort(int *a, int n,int dk) {
    for (int i = dk; i < n; ++i) {
        int j = i - dk;
        if (a[i] < a[j]) {    //    比较前后数字大小
            int tmp = a[i];        //    作为临时存储
            a[i] = a[j];
            while (a[j] > tmp) {    //    寻找tmp的插入位置
                a[j+dk] = a[j];
                j -= dk;
            }
            a[j+dk] = tmp;        //    插入tmp
        }
    }
}

void ShellSrot(int *a, int n) {
    int dk = n / 2;        //    设置初始dk
    while (dk >= 1) {
        Insrtsort(a, n, dk);
        dk /= 2;
    }
}

int main() {
    int a[] = { 5,12,35,42,11,2,9,41,26,18,4 };
    int n = sizeof(a) / sizeof(int);
    ShellSrot(a, n);
    printf("排序好的数组为:");
    for (int j = 0; j < n; j++) {
        printf("%d ", a [j]);
    }
    return 0;
}

分析:

  最坏时间复杂度为O(n^2);最优时间复杂度为O(n);平均时间复杂度为O(n^1.3)。辅助空间O(1)。稳定性:不稳定。希尔排序的时间复杂度与选取的增量有关,选取合适的增量可减少时间复杂度。

三.选择排序

1.直接选择排序

基本思想:依次选出数组最小的数放到数组的前面。首先从数组的第二个元素开始往后遍历,找出最小的数放到第一个位置。再从剩下数组中找出最小的数放到第二个位置。以此类推,直到数组有序。

#include<stdio.h>
void SelectSort(int *a, int n) {
    for (int i = 0; i < n; i++)
    {
        int key = i;    //    临时变量用于存放数组最小值的位置
        for (int j = i + 1; j < n; j++) {
            if (a[j] < a[key]) {
                key = j;    //    记录数组最小值位置
            }
        }
            if (key != i)
            {
                int tmp = a[key]; a[key] = a[i]; a[i] = tmp;    //    交换最小值
            }

    }
}
int main() {
    int a[] = { 12,4,15,2,6,22,8,10,1,33,45,24,7 };
    int n = sizeof(a) / sizeof(int);
    SelectSort(a, n);
    printf("排序好的数组为: ");
    for (int k = 0; k < n; k++)
        printf("%d ", a[k]);
    printf("\n");
    return 0;
}

分析:

  最差、最优、平均时间复杂度都为O(n^2)。辅助空间为O(1)。稳定性:不稳定。

2.堆(Heap)排序

  基本思想:先把数组构造成一个大顶堆(父亲节点大于其子节点),然后把堆顶(数组最大值,数组第一个元素)和数组最后一个元素交换,这样就把最大值放到了数组最后边。把数组长度n-1,再进行构造堆,把剩余的第二大值放到堆顶,输出堆顶(放到剩余未排序数组最后面)。依次类推,直至数组排序完成。

#include<stdio.h>
void CreatHeap(int a[], int i,int  n) {
    //    从第一个非叶子结点i(n/2-1)从下至上,从右至左调整结构
    //    从两个儿子节点中选出较大的来与父亲节点进行比较
    //    如果儿子节点比父亲节点大,则进行交换
        int temp = a[i];    //    保存当前父亲节点元素
        for (int k = i * 2 + 1; k <= n; k = k * 2 +1)
        {
            if (k < n && a[k+1]>a[k])    //    比较左右子节点大小,选择较大者
                k++;
            //    比较父亲节点与儿子节点,当父亲节点比儿子节点小,儿子节点赋值给父亲节点

            if (temp < a[k]) {
                a[i] = a[k];
                i = k;
            }
            else
                break;
        }
        a[i] = temp;    //    将temp放到最终位置
}

//    进行堆排序,依次选出最大值放到最后面
void HeapSort(int a[], int n) {
    //    初始化构造堆
    for(int i=n/2-1;i>=0;i--)
        CreatHeap(a,i, n);
    for (int j = n -1; j >= 0; j--) {
        //    最后一个元素和第一个元素进行交换
        int tmp = a[0];
        a[0] = a[j];
        a[j] = tmp;
        //重建被破坏的堆
        CreatHeap(a,0,j-1);
    }
}
int main() {
    int a[] = { 10,6,5,7,12,8,1,3,11,4,2,9 };
    int n = sizeof(a) / sizeof(int);
    HeapSort(a, n);
    printf("排序好的数组为:");
    for (int l = 0; l < n; l++) {
        printf("%d ", a[l]);
    }
    printf("\n");
    return 0;
}

分析:

  最差、最优‘平均时间复杂度都为O(nlogn)。辅助空间O(1)。稳定性:不稳定。

四.归并排序

  基本思想:归并算法应用到分治策略,简单说就是把一个答问题分解成易于解决的小问题后一个个解决,最后在把小问题的一步步合并成总问题的解。这里的排序应用递归来把数组分解成一个个小数组,直到小数组的数位有序,在把有序的小数组两两合并而成有序的大数组。

#include <stdio.h>
#include <limits.h>

// 合并两个已排好序的数组
void Merge(int a[], int left, int mid, int right)
{
    int len = right - left + 1;        //    数组的长度
    int *temp = new int[len];       // 分配个临时数组
    int k = 0;
    int i = left;                   // 前一数组的起始元素
    int j = mid + 1;                // 后一数组的起始元素
    while (i <= mid && j <= right)
    {
        //    选择较小的存入临时数组
        temp[k++] = a[i] <= a[j] ? a[i++] : a[j++];
    }
    while (i <= mid)
    {
        temp[k++] = a[i++];
    }
    while (j <= right)
    {
        temp[k++] = a[j++];
    }
    for (int k = 0; k < len; k++)
    {
        a[left++] = temp[k];
    }
}

// 递归实现的归并排序
void MergeSort(int a[], int left, int right)
{
    if (left == right)
        return;
    int mid = (left + right) / 2;
    MergeSort(a, left, mid);
    MergeSort(a, mid + 1, right);
    Merge(a, left, mid, right);
}

int main() {
    int a[] = { 5,1,9,2,8,7,10,3,4,0,6 };
    int n = sizeof(a) / sizeof(int);
    MergeSort(a, 0, n - 1);
    printf("排序好的数组为:");
    for (int k = 0; k < n; ++k)
        printf("%d ", a[k]);
    printf("\n");
    return 0;
}

分析:

  最差、最优、平均时间复杂度都为O(nlogn)。辅助空间O(n)。稳定性:稳定。

  

时间: 2025-01-14 17:36:38

常用七大排序算法总结(C语言描述)的相关文章

几种经典排序算法的R语言描述

1.数据准备 # 测试数组 vector = c(5,34,65,36,67,3,6,43,69,59,25,785,10,11,14) vector ## [1] 5 34 65 36 67 3 6 43 69 59 25 785 10 11 14 2.R语言内置排序函数 在R中和排序相关的函数主要有三个:sort(),rank(),order(). sort(x)是对向量x进行排序,返回值排序后的数值向量; rank()是求秩的函数,它的返回值是这个向量中对应元素的“排名”; order()

链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述

关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学习过算法的系统性的课程,现在还是处于不断摸索的阶段,好多算法题目根本就没有什么思路,导致自己对好多题目都很是头疼,就算是自己做过的一些算法的题目,再次遇到也还是不一定会做出来,他给出的建议就是,看懂别人的程序,然后自己去敲,一定会出错,然后调试,有错误接着调试,一直到没有错误为止,并且要时常的去复习

常用排序算法的C语言实现

最近看数据结构,把常用的排序算法用C语言写了一下. 没有按数据结构上的定义SqList结构体,只是用数组的形式实现. 有的算法并没有完全按书上给出的算法,但思路一致. #include<stdio.h> void InsertSort(int[], int); //直接插入排序 无哨兵 void BInsertSort(int[], int); //折半插入排序 void BubbleSort(int[], int); //起泡排序 void QSort(int[], int, int); /

【最全】经典排序算法(C语言)

本文章包括所有基本排序算法(和其中一些算法的改进算法): 直接插入排序.希尔排序.直接选择排序.堆排序.冒泡排序.快速排序.归并排序.基数排序. 算法复杂度比较: 算法分类 一.直接插入排序 一个插入排序是另一种简单排序,它的思路是:每次从未排好的序列中选出第一个元素插入到已排好的序列中. 它的算法步骤可以大致归纳如下: 从未排好的序列中拿出首元素,并把它赋值给temp变量: 从排好的序列中,依次与temp进行比较,如果元素比temp大,则将元素后移(实际上放置temp的元素位置已经空出) 直到

深入排序算法的多语言实现

深入浅出排序算法的多语言实现 作者:白宁超 2015年10月8日20:08:11 摘要:十一假期于实验室无趣,逐研究起数据结构之排序.起初觉得就那么几种排序,两三天就搞定了,后来随着研究的深入,发觉里面有不少东西.本文介绍常用的排序算法,主要从以下几个方面:算法的介绍.算法思想.算法步骤.算法优缺点.算法实现.运行结果.算法优化等.最后对本文进行总结.本文为作者原创,程序经测试无误.部分资料引用论文和网络材料以及博客,后续参见参考文献.(本文原创,转载注明出处) 1 排序的基本概念 排序: 所谓

7 种常用的排序算法-视觉直观感受

7 种常用的排序算法-可视化 1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性. 步骤: 从数列中挑出一个元素,称为 “基准”(pivot),

java SE 常用的排序算法

java程序员会用到的经典排序算法实现 常用的排序算法(以下代码包含的)有以下五类: A.插入排序(直接插入排序.希尔排序) B.交换排序(冒泡排序.快速排序) C.选择排序(直接选择排序.堆排序) D.归并排序 E.分配排序(基数排序) 以下算法都是可以实现的,但是什么情况使用什么算法都是根据实际情况选用的. 如果有用的话就顶起吧,谢谢. import java.util.ArrayList; import java.util.List; public class Sort { // test

排序算法总结(C语言版)

1.    插入排序 1.1     直接插入排序 1.2     Shell排序 2.    交换排序 2.1     冒泡排序 2.2     快速排序 3.    选择排序 3.1     直接选择排序 3.2     堆排序 4.    归并排序 4.1     二路归并排序 4.2     自然合并排序 5.    分布排序 5.1     基数排序 1.插入排序 1.1      直接插入排序 将已排好序的部分num[0]~num[i]后的一个元素num[i+1]插入到之前已排好序的

JavaScript实现常用的排序算法

▓▓▓▓▓▓ 大致介绍 由于最近要考试复习,所以学习js的时间少了 -_-||,考试完还会继续的努力学习,这次用原生的JavaScript实现以前学习的常用的排序算法,有冒泡排序.快速排序.直接插入排序.希尔排序.直接选择排序 ▓▓▓▓▓▓ 交换排序 交换排序是一类在排序过程中借助于交换操作来完成排序的方法,基本思想是两两比较排序记录的关键字,如果发现两个关键字逆序,则将两个记录位置互换,重复此过程,直到该排序列中所有关键字都有序为止,接下来介绍交换排序中常见的冒泡排序和快速排序 ▓▓▓▓▓▓