十种排序算法总结(代码及说明)

1.冒泡排序

基本思想是:两两比较相邻记录的关键字,如果反序则交换

冒泡排序时间复杂度最好的情况为O(n),最坏的情况是O(n^2)

改进思路1:设置标志位,明显如果有一趟没有发生交换(flag = false),说明排序已经完成

改进思路2:记录一轮下来标记的最后位置,下次从头部遍历到这个位置就Ok.

原冒泡排序代码如下:

void swap(int left, int right)
{
    left  = left ^ right;
    right = right ^ left;
    left  = left ^ right;
}

/*****************************************************************/
/* 冒泡排序时间复杂度最好的情况为O(n),最坏的情况是O(n^2)
* 基本思想是:两两比较相邻记录的关键字,如果反序则交换 */

void BubbleSort(int arr[], int num)
{
    int i, j;
    for (i = 0; i < num; i++)
    {
        for (j = 1; j < num - i - 1; j++)
        {
            if (arr[j] > arr[j + 1])
                swap(arr[j], arr[j + 1]);
        }
    }
}

2.改进思路1:

 // 改进思路:设置标志位,明显如果有一趟没有发生交换(flag = flase),说明排序已经完成.
void swap(int left, int right)
{
    left  = left ^ right;
    right = right ^ left;
    left  = left ^ right;
}
 void BubbleSort(int arr[], int num)
{
    int k = num;
    int j;
    bool flag = true;
    while (flag)
    {
        flag = false;
        for (j = 1; j < k; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                swap1(arr[j], arr[j + 1]);
                flag = true;
            }
        }
        k--;
    }
}

3.改进思想2:

//改进思路:记录一轮下来标记的最后位置,下次从头部遍历到这个位置就Ok
void BubbleSort3(int arr[], int num)
{
    int k, j;
    int flag = num;
    while (flag > 0)
    {
        k = flag;
        flag = 0;
        for (j = 1; j < k; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                swap1(arr[j], arr[j + 1]);
                flag = j;
            }
        }
    }
}

二.直接插入排序

将一个记录插入到已经排好序的有序表中, 从而得到一个新的,记录数增1的有序表

时间复杂度也为O(n^2), 比冒泡法和选择排序的性能要更好一些

代码如下:

/*插入排序: 将一个记录插入到已经排好序的有序表中, 从而得到一个新的,记录数增1的有序表
* 时间复杂度也为O(n^2), 比冒泡法和选择排序的性能要更好一些 */

void InsertionSort(int arr[], int num)
{
    int temp;
    int i, j;
    for (i = 1; i < num; i++)
    {
        temp = arr[i];
        for (j = i; j > 0 && arr[j - 1] > temp; j--)
            arr[j] = arr[j - 1];
        arr[j] = temp;
    }
}

三、简单选择排序

通过n-i次关键字之间的比较,从n-i+1 个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换之

尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序

代码如下:

/* 简单选择排序(simple selection sort) 就是通过n-i次关键字之间的比较,从n-i+1
* 个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换之
* 尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序 */

void swap(int left, int right)
{
    left  = left ^ right;
    right = right ^ left;
    left  = left ^ right;
}

<span style="color:#8000ff;">void</span> SelectSort(<span style="color:#8000ff;">int</span> arr[], <span style="color:#8000ff;">int</span> num)
{
    <span style="color:#8000ff;">int</span> i, j, Mindex;
    <span style="color:#0000ff;">for</span> (i = <span style="color:#ff0000;">0</span>; i < num; i++)
    {
        Mindex = i;
        <span style="color:#0000ff;">for</span> (j = i + <span style="color:#ff0000;">1</span>; j < num; j++)
        {
            <span style="color:#0000ff;">if</span> (arr[j] < arr[Mindex])
                Mindex = j;
        }

        swap1(&arr[i], &arr[Mindex]);
    }
}

四、希尔排序

先将整个待排元素序列分割成若干子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序(增量为1)。其时间复杂度为O(n^3/2),要好于直接插入排序的O(n^2)

<span style="font-size:18px;">/</span>*希尔排序:先将整个待排元素序列分割成若干子序列(由相隔某个“增量”的元素组成的)分别进行
直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,
再对全体元素进行一次直接插入排序(增量为1)。其时间复杂度为O(n^3/2),要好于直接插入排序的O(n^2) */
void ShellSort(int *arr, int N)
{
    int i, j, increment;
    int tmp;
    for (increment = N / 2; increment > 0; increment /= 2)
    {
        for (i = increment; i < N; i++)
        {
            tmp = arr[i];
            for (j = i; j >= increment; j -= increment)
            {
                if (arr[j - increment] > tmp)
                    arr[j] = arr[j - increment];
                else
                    break;
            }
            arr[j] = tmp;
        }

    }
}

五、归并排序

假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到(不小于n/2的最小整数)个长度为2或1的有序子序列,再两两归并,...如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。 时间复杂度为O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间 空间复杂度为O(n).

代码:

/*假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后
* 两两归并,得到(不小于n/2的最小整数)个长度为2或1的有序子序列,再两两归并,...
* 如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
* 时间复杂度为O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间
* 空间复杂度为O(n) */

/*lpos is the start of left half, rpos is the start of right half*/
void merge(int a[], int tmp_array[], int lpos, int rpos, int rightn)
{
    int i, leftn, num_elements, tmpos;

    leftn = rpos - 1;
    tmpos = lpos;
    num_elements = rightn - lpos + 1;

    /*main loop*/
    while (lpos <= leftn && rpos <= rightn)
        if (a[lpos] <= a[rpos])
            tmp_array[tmpos++] = a[lpos++];
        else
            tmp_array[tmpos++] = a[rpos++];

    while (lpos <= leftn) /*copy rest of the first part*/
        tmp_array[tmpos++] = a[lpos++];
    while (rpos <= rightn) /*copy rest of the second part*/
        tmp_array[tmpos++] = a[rpos++];

    /*copy array back*/
    for (i = 0; i < num_elements; i++, rightn--)
        a[rightn] = tmp_array[rightn];
}

void msort(int a[], int tmp_array[], int left, int right)
{
    int center;

    if (left < right)
    {
        center = (right + left) / 2;
        msort(a, tmp_array, left, center);
        msort(a, tmp_array, center + 1, right);
        merge(a, tmp_array, left, center + 1, right);
    }
}

void merge_sort(int a[], int n)
{
    int *tmp_array;
    tmp_array = (int *)malloc(n * sizeof(int));

    if (tmp_array != NULL)
    {
        msort(a, tmp_array, 0, n - 1);
        free(tmp_array);
    }

    else
        printf("No space for tmp array!\n");
}

六、堆排序

堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆。

/* 堆是具有下列性质的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;
* 或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆*/

/*堆排序就是利用堆进行排序的方法.基本思想是:将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是堆顶
* 的根结点.将它移走(其实就是将其与堆数组的末尾元素交换, 此时末尾元素就是最大值),然后将剩余的n-1个序列重新
* 构造成一个堆,这样就会得到n个元素的次大值.如此反复执行,便能得到一个有序序列了
*/
/* 时间复杂度为 O(nlogn),好于冒泡,简单选择,直接插入的O(n^2) */

// 构造大顶堆
#define leftChild(i) (2*(i) + 1)

void percDown(int *arr, int i, int N)
{
    int tmp, child;
    for (tmp = arr[i]; leftChild(i) < N; i = child)
    {
        child = leftChild(i);
        if (child != N - 1 && arr[child + 1] > arr[child])
            child++;
        if (arr[child] > tmp)
            arr[i] = arr[child];
        else
            break;
    }
    arr[i] = tmp;
}

void HeapSort(int *arr, int N)
{
    int i;
    for (i = N / 2; i >= 0; i--)
        percDown(arr, i, N);
    for (i = N - 1; i > 0; i--)
    {
        swap1(&arr[0], &arr[i]);
        percDown(arr, 0, i);
    }
}

int main(void)
{
    int arr[] = { 9, 2, 5, 8, 3, 4, 7, 1, 6, 10};
    HeapSort(arr, 10);
    for (int i = 0; i < 10; i++)
        cout << arr[i] << ' ';
    cout << endl;

    return 0;
}

七:计数排序

计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。

算法的步骤如下:

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i
  3. 对所有的计数累加(从C中的位置为1的元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存

/*****************计数排序*******************************/
void  CountSort(int *arr, int num)
{
    int mindata = arr[0];
    int maxdata = arr[0];
    for (int i = 1; i < num; i++)
    {
        if (arr[i] > maxdata)
            maxdata = arr[i];
        if (arr[i] < mindata)
            mindata = arr[i];
    }

    int size = maxdata - mindata + 1;
    //申请空间并初始化为0
    int *pCount = (int *)malloc(sizeof(int) * size);
    memset(pCount, 0, sizeof(int)*size);

    //记录排序计数,每出现一次在对应位置加1
    for (int i = 0; i < num; i++)
        ++pCount[arr[i]-mindata];

    //确定不比该位置大的数据个数
    for (int i = 1; i < size; i++)
        pCount[i] += pCount[i - 1]; //加上前一个的计数

    int *pSort = (int *)malloc(sizeof(int) * num);
    memset((char*)pSort, 0, sizeof(int) * num);

    //从末尾开始拷贝是为了重复数据首先出现的排在前面,即稳定排序
    for (int i = num - 1; i >= 0; i--)
    {
        //包含自己需要减1,重复数据循环回来也需要减1
        --pCount[arr[i]-mindata];
        pSort[pCount[arr[i]-mindata]] = arr[i];
    }
    //拷贝到原数组
    for (int i = 0; i < num; i++)
        arr[i] = pSort[i];

    free(pCount);
    free(pSort);

}

八:桶排序

桶排序
(Bucket sort)或所谓的箱排序,是一个排序算法,工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)

桶排序以下列程序进行:

  1. 设置一个定量的数组当作空桶子。
  2. 寻访串行,并且把项目一个一个放到对应的桶子去。(hash)
  3. 对每个不是空的桶子进行排序。
  4. 从不是空的桶子里把项目再放回原来的串行中。

struct Node
{
    int key_;
    struct Node *next_;
    Node(int key)
    {
        key_ = key;
        next_ = NULL;
    }
};

#define bucket_size 10 //与数组元素个数相等

void buck_sort(int arr[], int num)
{
    Node *bucket_table[bucket_size];
    memset(bucket_table, 0, sizeof(bucket_table));

    //建立每一个头节点,头节点的key保存当前桶的数据量
    for (int i = 0; i < bucket_size; i++)
        bucket_table[i] = new Node(0);

    int maxValue = arr[0];
    for (int i = 1; i < num; i++)
    {
        if (arr[i] > maxValue)
            maxValue = arr[i];
    }

    for (int j = 0; j < num; j++)
    {
        Node *ptr = new Node(arr[j]);//其余节点的key保存数据

        //映射函数计算桶号
        // index = (value * number_of_elements) / (maxvalue + 1)
        int index = (arr[j] * bucket_size) / (maxValue + 1);
        Node *head = bucket_table[index];
        //该桶还没有数据
        if (head->key_ == 0)
        {
            bucket_table[index]->next_ = ptr;
            (bucket_table[index]->key_)++;

        }
        else
        {
            //找到合适的位置插入
            while (head->next_ != NULL && head->next_->key_ <= ptr->key_)
                head = head->next_;
            ptr->next_ = head->next_;
            head->next_ = ptr;
            (bucket_table[index]->key_)++;
        }

    }

    //将桶中的数据拷贝回原数组
    int m, n;
    for (m = 0, n = 0;  n < num && m < bucket_size; m++, n++)
    {
        Node *ptr = bucket_table[m]->next_;
        while (ptr != NULL)
        {
            arr[n] = ptr->key_;
            ptr = ptr->next_;
            n++;
        }
        n--;
    }

    //释放分配的动态空间
    for (m = 0; m < bucket_size; m++)
    {
        Node *ptr = bucket_table[m];
        Node *tmp = NULL;
        while (ptr != NULL)
        {
            tmp = ptr->next_;
            delete ptr;
            ptr = tmp;
        }

    }

}

九.基数排序

基数排序(英语:Radix
sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

它是这样实现的:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。

void base_sort_ISD(int *arr, int num)
{
    Node *buck[10]; // 创建一个链表数组
    Node *tail[10]; //保存每条链表尾节点指针集合,
    //这样插入buck数组时就不用每次遍历到末尾
    int  i, MaxValue, kth, high, low;
    Node *ptr;
    for(MaxValue = arr[0], i = 1; i < num; i++)
        MaxValue = max(MaxValue, arr[i]);

    memset(buck, 0, sizeof(buck));
    memset(tail, 0, sizeof(buck));

    for(low = 1; high = low * 10, low < MaxValue; low *= 10)
    {
        //只要没排好序就一直排序
        for(i = 0; i < num; i++)
        {
            //往桶里放
            kth = (arr[i] % high) / low;//取出数据的某一位,作为桶的索引
            ptr = new Node(arr[i]); //创建新节点

            //接到末尾
            if (buck[kth] != NULL)
            {
                tail[kth]->next_ = ptr;
                tail[kth] = ptr;
            }
            else
            {
                buck[kth] = ptr;
                tail[kth] = ptr;
            }

        }
        //把桶中的数据放回数组中(同条链表是从头到尾)
        for (kth = 0, i = 0; kth < num; i++)
        {
            while (buck[i] != NULL)
            {
                arr[kth++] = buck[i]->key_;
                ptr = buck[i];
                buck[i] = buck[i]->next_;
                delete ptr;
            }
        }

        memset(tail, 0, sizeof(buck));

    }

}

十.快速排序

原文地址:地址

时间: 2024-10-06 13:35:47

十种排序算法总结(代码及说明)的相关文章

Python实现各种排序算法的代码示例总结

Python实现各种排序算法的代码示例总结 作者:Donald Knuth 字体:[增加 减小] 类型:转载 时间:2015-12-11我要评论 这篇文章主要介绍了Python实现各种排序算法的代码示例总结,其实Python是非常好的算法入门学习时的配套高级语言,需要的朋友可以参考下 在Python实践中,我们往往遇到排序问题,比如在对搜索结果打分的排序(没有排序就没有Google等搜索引擎的存在),当然,这样的例子数不胜数.<数据结构>也会花大量篇幅讲解排序.之前一段时间,由于需要,我复习了

排序算法总结---代码+性能

// data_sort_alg.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "sort_alg.h" #include <iostream> #include <vector> void show(std::vector<int> &a) { std::vector<int>::iterator it=a.begin(); while(it!=a.

各种排序算法的代码

1 // ALLKindsOfSorts.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 #include<vector> 7 #include<bitset> 8 9 using namespace std; 10 11 ////////////////////////////////////////所有的排序总结///////////////////

数据结构——常见的十种排序算法

一.常见的十种排序算法: 冒泡排序.选择排序.插入排序.归并排序.快速排序.希尔排序.堆排序.计数排序.桶排序.基数排序 1.[知识框架] 补充:内部排序:整个排序过程完全在内存中进行. 外部排序:由于待排序记录数据量太大,内存无法容纳全部数据,需要借助外部存储. 二.排序方法 ?插入排序 1.算法思想 从待排序的第二个元素开始,向下扫描列表,比较这个目标值target与arr[i-1].arr[i-2]的大小,依次类推.如果target的值小于或等于每一个元素值,那么每个元素都会向右滑动一个位

C言语疾速排序算法及代码

疾速排序是对冒泡法排序的一种改良.疾速排序算法 的根本思惟是:将所要停止排序的数分为阁下两个局部,个中一局部的一切数据都比别的一 局部的数据小,然后将所分得的两局部数据停止异样的划分,反复履行以上的划分操作,直 到一切要停止排序的数据变为有序为止.能够仅依据根本思惟对疾速排序的看法并不深,接下来以对n个无序数列A[0], A[1]-, A[n-1]采取疾速排序办法停止升序陈列为例停止解说.(1)界说两个变量low和high,将low.high辨别设置为要停止排序的序列的肇端元素和最初一个元素的下

十大排序算法 JAVA代码

冒泡排序 插入排序 选择排序 希尔排序 归并排序 快速排序 堆排序 计数排序 基数排序 桶排序  O是指计算机执行命令所需的时间 nlogn是算法的时间复杂度,一般排序用的是log2n 总体总结表:这个有个错误就是归并排序需要一个o(n)的辅助数组  冒泡排序 主要思想:外层循环从1到n-1,内循环从当前外层的元素的下一个位置开始,依次和外层的元素比较,出现逆序就交换. 特点:stable sort(稳定性排序).In-place sort(不占用额外的空间,只是交换元素) 最优复杂度:当输入数

简单的选择排序算法实现代码

1 #include<stdio.h> 2 #define N 12 3 //length统计数组的长度 返回最后元素的下标 4 int length(int a [N]){ 5 for(int i = 0;i<=N;i++){ 6 if(a[i]==0) return i-1; 7 8 } 9 } 10 //打印输出数组元素 11 void show(int a[N]){ 12 for(int i= 0;i<N;i++){ 13 if(a[i]!=0) printf("

C言语选择排序算法及代码

选择排序是排序算法的一种,这里以从小到大排序为例停止解说. 根本思惟及举例阐明 选择排序(从小到大)的根本思惟是,起首,选出最小的数,放在第一个地位:然后,选出第二小的数,放在第二个地位:以此类推,直到一切的数从小到大排序.在完成上,我们平日是先肯定第i小的数地点的地位,然后,将其与第i个数停止交流.下面,以对 3  2  4  1 停止选择排序阐明排序进程,运用min_index 记载以后最小的数地点的地位.第1轮 排序进程 (寻觅第1小的数地点的地位)3  2  4  1(最后, min_i

C言语拔出排序算法及代码

拔出排序是排序算法的一种,它不改动原有的序列(数组),而是创立一个新的序列,在新序列长进行操作.这里以从小到大排序为例停止解说. 根本思惟及举例阐明 拔出排序的根本思惟是,将元素逐一添加到曾经排序好的数组中去,同时请求,拔出的元素必需在准确的地位,如许本来排序好的数组是依然有序的.在实践运用中,平日是排序全部无序数组,所以把这个无序数组分为两局部排序好的子数组和待拔出的元素.第一轮时,将第一个元素作为排序好的子数组,拔出第二个元素:第二轮,将前两个元素作为排序好的数组,拔出第三个元素.以此类推,