常见的几种排序算法(c++)

一、冒泡排序

1、算法思想

冒泡排序是一种简单的排序算法,通过循环遍历,将临近的两个元素进行比较,满足排序规则时,进行下一组元素对比,当不满足排序规则时,将两个元素交换位置,再继续进行下一组元素对比,确保最大的元素在一遍循环过后一定排在最后面,然后最后通过最多n2次循环对比,直到完全有序。

2、算法描述
冒泡过程.gif

(1)比较两个相邻的元素,如果第一个比第二个大,那么就交换他们的位置。
(2)重复步骤(1)的操作,依次比较两两相邻的两个元素。所有元素对比过后表示一次循环结束。
(3)至多循环n-1次,重复上面两个步骤。
(4)直到没有任何一组元素需要交换位置表示排序完成。

3、代码实现
void BubbleSort(int* slist,int length)
{
    int temp;
    for (int i = 0; i < length - 1; i++)
    {
        for (int j = 0; j < length - 1 - i; j++)
        {
            if (slist[j] > slist[j + 1])
            {
                temp = slist[j];
                slist[j] = slist[j + 1];
                slist[j + 1] = temp;
            }
        }
    }
}
int main()
{
    int sortlist[] = { 5,0,4,1,8,3,7 };
    BubbleSort(sortlist,7);
}
4、算法复杂度

最好的情况为正序,只需要一遍遍历,所以时间复杂度为O(n),最坏的情况为逆序,需要遍历n2次,所以时间复杂度为O(n2)。由于只有一个交换的变量temp需要内存,所以空间复杂度为O(1)。

二、插入排序

1、算法思想

将列表中的每个元素依次和之前排好序的元素进行比较,找到合适的位置插入,使之前有序的列表保持依然有序。

2、算法描述
插入排序.gif

(1)从第2个元素开始,选取第2个元素(i),认为第1个元素为一个只有一个元素的有序列表。
(2)将选取的元素与之前的元素依次比较,如果选取的元素小于于列表中的元素,交换他们的位置。
(3)选取下一个元素(i+1),重复步骤(2),直至列表中的每个元素都进行了步骤(2)的操作。

3、代码实现
//方法一
void InsertSort1(int* slist,int length)
{
    int temp;
    for (int i = 1; i < length; i++)
    {
        int j = i -1;
        while (slist[j] > slist[j+1] && j >= 0)
        {
            //交换位置
            temp = slist[j];
            slist[j] = slist[j+1];
            slist[j+1] = temp;
            j--;

            /*或者这样交换*/
            // slist[j+1] = slist[j] + slist[j+1];
            // slist[j] = slist[j+1] - slist[j];
            // slist[j+1] = slist[j+1] - slist[j];
            // j--;
        }
        
    } 
}

//方法二
void InsertSort2(int* slist,int length)
{
    for (int i = 1; i < length; i++)
    {
        int j = i - 1;
        int number = slist[i];
        while (j >= 0 && slist[j] > number)
        {
            slist[j+1] = slist[j];
            j--;
        }
        slist[j+1] = number; 
    } 
}
4、算法复杂度

最好的情况为正序,只需要一遍遍历,所以时间复杂度为O(n),最坏的情况为逆序,需要遍历n2次,所以时间复杂度为O(n2)。空间复杂度为O(1)。

三、选择排序

1、算法思想

从头开始,遍历列表找到最小值,把最小的值放在第一个位置,在遍历找到第二小的值放在第一个后面,以此类推,知道最后一个排好序。

2、算法描述
选择排序.jpg

(1)遍历整个列表N个元素,找到最小的元素,与第一个元素交换位置。
(2)遍历剩余的N-1个元素,找到最小的元素,将它排在剩余N-1个元素的第一个。
(3)以此类推,重复步骤(2),直到N-1小于1。

3、代码实现
void SelectSort(int* slist, int length)
{
    int min;
    int temp;
    for (int i = 0; i < length; i++)
    {
        min = i;
        for (int j = i + 1; j < length; j++)
        {
            if (slist[j] < slist[min])
            {
                min = j;
            }
        }
        temp = slist[i];
        slist[i] = slist[min];
        slist[min] = temp;
    }
}
4、算法复杂度

不管最后还是最坏的情况,选择排序的时间复杂度都是O(n2),空间复杂度为O(1)。

四、归并排序

1、算法思想

归并排序采用分治的思想,将一个列表分为多个子列表,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

2、算法描述
归并排序.png

(1)将列表元素对半分开,分为两个列表。
(2)重复步骤(1),直至每个列表只有一个元素。
(3)将两个相邻的列表排序,直至真个列表有序。

3、代码实现
//排序
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int midIndex, int endIndex)
{
    //i:第一个待排序的起始位置,
    int i = startIndex;
    //j:第二个待排序的起始位置,
    int j = midIndex + 1;
    int k = startIndex;

    while (i != midIndex + 1 && j != endIndex+1)
    {
        if (sourceArr[i] > sourceArr[j])
        {
            tempArr[k] = sourceArr[j];
            k++;
            j++;
        }
        else
        {
            tempArr[k] = sourceArr[i];
            k++;
            i++;
        }    
    }
    //将两个中未排序的添加到tempArr中
    while (i != midIndex + 1)
    {
        tempArr[k] = sourceArr[i];
        i++;
        k++;
    }
    //将两个中未排序的添加到tempArr中
    while (j != endIndex+1)
    {
        tempArr[k] = sourceArr[j];
        j++;
        k++;
    }

    //将tempArr中的元素赋值给sourceArr
    for (int i = startIndex; i <= endIndex; i++)
    {
        sourceArr[i] = tempArr[i];
    }
}

//分解递归
void BranchSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    if (startIndex < endIndex)
    {
        int mid = startIndex + (endIndex - startIndex) / 2;
        BranchSort(sourceArr, tempArr, startIndex, mid);
        BranchSort(sourceArr, tempArr, mid+1, endIndex);
        MergeSort(sourceArr, tempArr, startIndex, mid, endIndex);
    }
}
4、算法复杂度

归并排序是稳定排序算法,假设数组长度为n,那么拆分数组共需logn, 又每步都是一个普通的合并子数组的过程,时间复杂度为O(n), 故其综合时间复杂度为O(nlogn)。另一方面, 归并排序多次递归过程中拆分的子数组需要保存在内存空间, 其空间复杂度为O(n)。

五、希尔排序

1、算法思想

希尔排序,也称递减增量排序算法。将整个列表根据增量分为若干个子列表分别进行插入排序。随着增量的减小,列表趋于基本有序,当增量为1时,相当再做一次插入排序,使列表有序。

2、算法描述
希尔排序.png

(1)选择一个增量gap,一般为列表长度的一半。
(2)将列表中元素下标每隔gap的元素组成一个新的子列表。
(3)对每个子列表进行插入排序。
(4)将gap去原来的一半,重复步骤(2)(3),直到gap小于1。

3、代码实现
void ShellSort(int* slist, int length)
{
    int temp;
    //gap为增量,一般取长度的一般
    int gap = length / 2;
    //当增量小于1时结束排序
    while (gap >= 1)
    {
        //最多分为gap个列表
        for (int i = 0; i < gap; i++)
        {
            //下面的代码为一个简单的插入排序,只是插入排序的数组下标每次移动的不是1而是gap
            for (int j = i+gap; j < length; j = j + gap)
            {
                if (slist[j] < slist[j-gap])
                {
                    int k = j - gap;
                    int temp = slist[j];
                    while (k >= 0 && slist[k] > temp)
                    {
                        slist[k + gap] = slist[k];
                        k = k - gap;
                    }
                    slist[k+gap] = temp;
                }
            }
        }
        //增量递减
        gap = gap/ 2;
    }
}
4、算法复杂度

希尔排序是不稳定的排序,它时间复杂度和步长的选择有关。
看如下两个增量序列:
n/2、n/4、n/8...1
1、3、7...2^k-1
第一个序列称为希尔增量序列,使用希尔增量时,希尔排序在最坏情况下的时间复杂度为O(n2)。
第二个序列称为Hibbard增量序列,使用Hibbard增量时,希尔排序在最坏情况下的时间复杂度为O(n3/2)。

六、快速排序

1、算法思想

快速排序采用分治的思想,通通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以 递归 进行,以此达到整个数据变成有序序列。

2、算法描述
快速排序.jpg

(1)选定一个基准元素
(2)从右往左找到比基准元素小的元素
(3)从左往右找到比基准元素大的元素
(4)交换左右找到的两个元素的位置
(5)重复上面(2)(3)(4)步,直至左右两个元素相遇。

3、代码实现
void QuickSort(int* slist, int left, int right)
{
    if (left >= right)
    {
        return;
    }
    int i = left;
    int j = right;
    int key = slist[left];
    int temp;

    //直到遍历完整个列表
    while (i < j)
    {
        //从右到左找到小于key的下标
        while (i<j&&slist[j] >= key)
        {
            j--;
        }
        //从左到右找到大于key的下标
        while (i<j && slist[i] <= key)
        {
            i++;
        }
        //交换找到的两个元素,保证小的元素在前,大的元素在后
        if (i < j)
        {
            temp = slist[i];
            slist[i] = slist[j];
            slist[j] = temp;
        }
    }
    //将key元素交换到中间,确保分为大小两个列表
    temp = slist[left];
    slist[left] = slist[j];
    slist[j] = temp;
    QuickSort(slist, left, j - 1);
    QuickSort(slist, j + 1, right);
}
void QuickSort2(int* slist, int left, int right)
{
    if (left >= right)
    {
        return;
    }
    int j = left-1;
    int key = slist[right];
    int temp;

    for (int i = left; i < right; i++)
    {
        //遍历整个列表,找到小于key的元素个数,并且通过交换位置,让他们的下标都在j的前面
        if (slist[i] < key)
        {
            j++;
            if (i != j)
            {
                temp = slist[i];
                slist[i] = slist[j];
                slist[j] = temp;
            }
        }
    }
    //将key的位置与j+1的位置互换,保证将slist列表分为小于slist[j+1]与大于slist[j+1]的两个列表
    slist[right] = slist[j + 1];
    slist[j + 1] = key;
    QuickSort2(slist,left,j);
    QuickSort2(slist, j+2, right);
}
4、算法复杂度

快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,753评论 0 13
  • Ba la la la ~ 读者朋友们,你们好啊,又到了冷锋时间,话不多说,发车! 1.冒泡排序(Bub...
    王饱饱阅读 1,794评论 0 7
  • 我一直觉得写代码也可以写出艺术,在不懂画的人的眼里,《向日葵》不过是小孩子的涂鸦,在懂代码的人眼里,那看似混乱的字...
    AidenRao阅读 4,152评论 9 59
  • 本文转自公众号 「程序员私房菜 」 一直有写一篇关于排序算法文章的打算,直到我看到了这一篇,我放弃了自己写的打算,...
    KEEPINUP阅读 2,442评论 4 15
  • (原创,转载请注明出处) 前些日苏城一场大雪,一周后的今天,仍未完全化去。这实属难得,换做往年,别说一周,...
    木晓冬阅读 201评论 0 2