排序(四)交换排序

1.冒泡排序(时间复杂度为 O(N2))

原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换,

这样一趟过去后,最大或最小的数字被交换到了最后一位;重复此动作直到排好序为止;

先来cv一个动图看看效果:

void BubbleSort(vector<int>& Vector)
{
    for (int i = 0; i < Vector.size(); ++i)
    {
        for (int j = 0; j < Vector.size() - i - 1; ++j)
        {
            if (Vector[j] > Vector[j + 1])
                swap(Vector[j], Vector[j + 1]);
        }
    }
}

/*优化*/
void OptimizeBubbleSort(vector<int>& Vector)
{
    int index = Vector.size() - 1;
    bool sign = true;
    while (index && sign)
    {
        int tmp = -1;
        for (int i = 0; i < index; ++i)
        {
            if (Vector[i] > Vector[i + 1])
            {
                swap(Vector[i], Vector[i + 1]);
                tmp = i;
            }

        }
        tmp > 0 ? index = tmp : sign = false;
    }
}

这里奉上一篇关于冒泡排序的博文(超赞): http://blog.csdn.net/lemon_tree12138/article/details/50591859

2.快速排序

快速排序也是一种采用分治法解决问题的一个典型应用。在很多编程语言中,对数组,列表进行的非稳定排序在内部实现中都使用的是快速排序。

借鉴前辈们的动图看下效果先:

快速排序的基本思想如下:

  1. 对数组进行随机化。
  2. 每次从数列中取出最后一个数作为参照;
  3. 将比这个数大或者等于的数放到它的右边,小于它的数放到它的左边。
  4. 再对左右区间重复第三步,直到各区间只有一个数。

举个栗子:

/*方式一:见上图 ↑↑↑↑↑↑*/int _QuickSort(vector<int>& Vector, int left, int right)
    {
        int middle = left + (right - left) / 2;
        /*优化一:三数取中*/
        int MaxNumber = Max(Vector[left],Max(Vector[middle], Vector[right]));
        int MinNumber = Min(Vector[left],Min(Vector[middle], Vector[right]));
        if (Vector[left] > MinNumber && Vector[left] < MaxNumber)
            swap(Vector[left], Vector[right]);
        else if (Vector[middle] > MinNumber && Vector[middle] < MaxNumber)
            swap(Vector[middle],Vector[right]);
        int begin = left, end = right - 1;
        int key = Vector[right];
        while (begin < end)
        {
            while (begin < end && Vector[begin] < key)
                ++begin;
            while (begin < end && Vector[end] >= key)
                --end;
            swap(Vector[begin], Vector[end]);
        }
        if (Vector[begin] > key)
        {
            swap(Vector[begin], Vector[right]);
            return begin;
        }
        else
        {
            return right;
        }
    }

/*方式二;挖坑法*/
int _QuickSort(vector<int>& Vector, int left, int right)
    {
        int begin = left, end = right;
        int key = Vector[right];
        while (begin < end)
        {
            while (begin < end && Vector[begin] < key)    ++begin;
                Vector[end] = Vector[begin];
            while (begin < end &&Vector[end] >= key) --end;
                Vector[begin] = Vector[end];
        }
        Vector[begin] = key;
        return begin;
    }

/*方式三:前后指针法*/
int _QuickSort(vector<int>& Vector, int left, int right)
    {
        int begin = left, small = left - 1, end = right;
        int key = Vector[right];
        while (begin < end)
        {
            if (Vector[begin] < key)
            {
                ++small;
                swap(Vector[small], Vector[begin]);
            }
            ++begin;
        }
        swap(Vector[++small ], Vector[end]);
        return small;
    }
void QuickSort(vector<int>& Vector, int left, int right)
    {
        if (right - left > 13)    //优化二:当区间小到一定程度时,使用插入排序
        {
            int middle = _QuickSort(Vector, left, right);
            QuickSort(Vector, left, middle - 1);
            QuickSort(Vector, middle+1, right);
        }
        else
        {
            //插入排序
            InsertSort(Vector, left, right);
        }
    }

/*插入排序*/
void InsertSort(vector<int>& Vector, int left, int right)
    {
        for (int i = left; i<right; ++i)
        {
            int end = i;
            int key = Vector[end + 1];
            while (end >= left && Vector[end] > key)
            {
                Vector[end + 1] = Vector[end];
                --end;
            }
            Vector[end + 1] = key;
        }
    }

算法分析:

  1. 在最好的情况下,快速排序只需要大约nlgn次比较操作,在最坏的情况下需要大约1/2 n次比较操作。
  2. 在最好的情况下,每次的划分都会恰好从中间将序列划分开来,那么只需要lgn次划分即可划分完成,每一次划分都需要比较N次。
  3. 在最坏的情况下,即序列已经排好序的情况下,每次划分都恰好把数组划分成了0,n两部分,那么需要n次划分,但是比较的次数则变成了n, n-1, n-2,….1, 所以整个比较次数约 为 nnndf n(n-1)/2~n2/2.
  4. 平均情况下,快速排序需要大约1.39NlgN次比较,这比合并排序多了39%的比较,但是由于涉及了较少的数据交换和移动操作,他要比合并排序更快。
  5. 快速排序是非稳定性排序。
时间: 2024-08-25 02:15:33

排序(四)交换排序的相关文章

【内部排序】 交换排序与选择排序详解

交换排序:通过依次交换逆序的元素使其有序化的过程. 介绍两种交换排序: 冒泡排序,快速排序 冒泡法:从第一个元素开始,依次比较相邻的两个元素,如果逆序则交换,第一趟比较结束后,序列中最大的元素将移动到序列末尾,即第n个位置,第二趟将次大元素移动到n-1位置-- 多趟比较后,会形成有序序列,排序方法类似气泡慢慢向上浮动,因此成为冒泡法. 快速排序: 对冒泡的改进,将序列中的关键字和指定元素(枢轴)比较,将序列以枢轴划分,保证枢轴大于其左边所有数,小于其右边所有数. (枢轴的选取很关键,避免快排在局

SDUT 3401 数据结构实验之排序四:寻找大富翁

数据结构实验之排序四:寻找大富翁 Time Limit: 200 ms Memory Limit: 512 KiB Problem Description 2015胡润全球财富榜调查显示,个人资产在1000万以上的高净值人群达到200万人,假设给出N个人的个人资产值,请你快速找出排前M位的大富翁. Input 首先输入两个正整数N( N ≤ 10^6)和M(M ≤ 10),其中N为总人数,M为需要找出的大富翁数目,接下来给出N个人的个人资产,以万元为单位,个人资产数字为正整数,数字间以空格分隔.

排序(交换排序)

所谓交换排序就是依次比较两个相邻元素的大小并根据需求进行交换,这里有两种交换排序. 1.冒泡排序.冒泡排序就是依次比较两个相邻数字,把两个数字中较大的放后边(这是从小到大排序,如果是降序排列,则反过来),这样一轮跑下来最大的那个数字就放到了最后,所谓冒泡就是每次都拿到当前剩余数字中最大的那个并依次放置在其应该放在的位置.这里能看出来也不需要开新空间,但是每跑一趟都需要把剩下的数字都玩儿一遍,时间效率很大,也是n平方了. 2.快速排序,调用了递归的思想,每次在序列中找到一个数字,这个数字后续处理时

[Java]排序算法&gt;交换排序&gt;【冒泡排序】(O(N*N)/稳定/N较小/有序/顺序+链式)

1 冒泡排序 1.1 算法思想 交换排序的基本思想:两两比较待排序记录的关键字,一旦发现2个记录不满足次序要求时,则:进行交换,直到整个序列全部满足要求为止. 1.2 算法特征 属于[交换排序] 冒泡排序 快速排序 适用于[稳定性]:稳定 适用于[规模N]:较小 适用于[有序性]:有序 适用于[存储结构]:顺序存储 or 链式存储(二者均可) 相关口诀:[插冒归堆]好有序,[插冒]记录个数小,[插冒二选]时N方 1.3 算法实现 import java.util.Arrays; public c

排序四:冒泡排序

基本思想: 设待排序数据元素序列中的元素个数为n,最多做n-1趟,i = 1, 2, ..., n-1.在第 i 趟中从后向前,j = n-1, n-2, ..., i,两两比较 V[j-1] 和 V[j] 的关键字.如果发生逆序,则交换 V[j-1]和 V[j]. #include <stdio.h> void println(int array[], int len) { int i = 0; for(i=0; i<len; i++) { printf("%d "

排序四 希尔排序

要点 希尔(Shell)排序又称为缩小增量排序,它是一种插入排序.它是直接插入排序算法的一种威力加强版. 该方法因DL.Shell于1959年提出而得名. 希尔排序的基本思想是:把记录按下标的一定增量 gap 分组,对每组记录采用直接插入排序方法进行排序.随着增量逐渐减小,所分成的组包含的记录越来越多,到增量的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序. 我们来通过演示图,更深入的理解一下这个过程. 在上面这幅图中: 初始时,有一个大小为 10 的无序序列. 在第一趟排序

排序算法-交换排序(javascript)

思想:两两比较,一旦发现不满足次序要求时进行交换,知道整个序列满足排序要求. 典型:冒泡排序与快速排序. 冒泡排序 思想:比较相邻两个,逆序就交换,每次排序将最大的'下沉'或最小的'上浮'. function bubbleSort(arr){ const len = arr.length; let temp = 0; for(let i=0;i<len-1;i++){ for(let j=0;j<len-i-1;j++){ if(arr[j]>arr[j+1]){ temp = arr[

常见的排序算法——交换排序

一.冒泡排序 #include <iostream> using namespace std; void print_array(int a[], int n) { for(int i = 0; i < n; i++) cout << a[i] << " " ; cout << endl; } void bubble_sort(int a[], int n) { for(int i = 0; i < n; i++) { for

排序算法(四)——归并排序、基数排序

前面三篇文章分别介绍了插入排序.选择排序和交换排序,今天将最后两个排序讲完,分别是归并排序和基数排序. ****************************************************************************************************** 1.归并排序: 定义:所谓归并就是将两个或两个以上的有序文件合并成为一个新的有序文件.归并排序就是有n个记录的无序文件看成是由n个长度为1的有序子文件组成的文件,然后两两归并,得到n/2个长

内部排序算法(一):交换排序(冒泡排序,快速排序)

这是我的博文系列<内部排序算法>的第一篇.所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来.所谓内部排序,是指在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内.外存交换(外排序的定义则相反). 内部排序法按照策略可以划分为五类:插入排序.选择排序.交换排序.归并排序和分配排序.待排文件的存储方式采用顺序表(或直接用向量)作为存储结构(其他的存储结构还有以链表作为存储结构等). 在这个系列的博文中,我按照排序算法的给出,排序算法的分析(包括算法的时空复杂度