数据结构(11)_排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构(11)_排序相关的知识,希望对你有一定的参考价值。

1.排序的基本概念

1.1.排序的概念

定义:排序是计算机内经常进行的一种操作,其目的是将一组“无序”的数据调整为“有序”的数据元素。
数学定义:假设含有n个数据元素的序列为{R1,R2...Rn},其相应的关键字序列为:{K1,K2...Kn};这些关键字相互之间进行比较,即:在他们之间存在着这样的一个关系:Kp1 <= Kp2 <= ... <= Kpn按此固有关系将上式重新排列为:{Rp1, Rp2, ... Rpn}的操作称为排序。

1.2.排序的稳定性

技术分享图片
问题:什么按照总评排序后张无忌的排名比郭靖靠前呢?
排序的稳定性:
如果序列中有两个数据元素Ri和Rj,他们关键字的Ki == Kj,且排序之前,对象Ri排在Rj之前,但排序之后两者的顺序交互,则称这个排序方案是不稳定的。

1.3.多关键字排序

排序时需要比较的关键字有多个,排序结果首先按照关键字1进行,当关键字1相同,按照关键字2进行排序...
技术分享图片
多关键字的排序并不比单关键字复杂,只需要在定义比较操作时,同时考虑多个关键字即可!
多关键字排序实例:

class MulitKeySort : public Object
{
protected:
    int key1;
    int key2;
public:
    MulitKeySort(int k1, int k2)
    {
        key1 = k1;
        key2 = k2;
    }

    bool operator ==(const MulitKeySort& m)
    {
        return ( (key1==m.key1) && (key2==m.key2));
    }

    bool operator !=(const MulitKeySort& m)
    {
        return !(*this == m);
    }

    bool operator <(const MulitKeySort& m)
    {
        return ( (key1<m.key1) || ((key1==m.key1) && (key2<m.key2)));
    }

    bool operator >=(const MulitKeySort& m)
    {
        return !(*this < m);
    }

    bool operator >(const MulitKeySort& m)
    {
        return ( (key1>m.key1) || ((key1==m.key1) && (key2>m.key2)));
    }

    bool operator <=(const MulitKeySort& m)
    {
        return !(*this > m);
    }
};

//测试代码:
void test_1()
{
    MulitKeySort m1(3, 4);
    MulitKeySort m2(3, 3);

    cout << (m1 > m2) << endl;
}

1.4.排序的选择

排序中的关键操作

  • 比较:任意两个数据元素通过比较操作确定先后次序。
  • 交换:数据元素之间需要交换才能得到预期的结果。
    排序的选择依据:
  • 时间性能,关键性能差异体现在比较和交换的数量
  • 辅助存储空间:完成排序操作需要额外的存储空间,必要时可以“空间换时间”
  • 算法的实现复杂度:过于复杂的排序算法可能影响可读性和可维护性。

    1.5.排序类的设计

    继承自顶层父类Object,并且私有化所有构造途径,将各种排序算法设计为静态成员函数。
    技术分享图片

    class DTSort : public Object
    {
    private:
    DTSort();
    DTSort(const DTSort&);
    DTSort& operator =(const DTSort&);
    
    template < typename T >
    static void Swap(T& a, T& b)
    {
        T c(a);
        a = b;
        b = c;
    }
    };

    2.选择排序与插入排序

    2.1.选择排序

    基本思想:每次(例如第i次,i=0,1,2...,n-2)从后面n-1个待排列的的数据元素中选出关键字最新的元素,左右有序元素序列的i个元素。
    技术分享图片
    技术分享图片
    技术分享图片

    template < typename T >
    static void SelectSort(T array[], int len, bool min2max = true)
    {
        for(int i=0; i<len; i++)
        {
            int min = i;
    
            for(int j=i+1; j<len; j++)
            {
                if(min2max ? array[j]<array[min] : array[j]>array[min])
                {
                    min = j;
                }
            }
    
            if(i != min)
            {
                Swap(array[i], array[min]);
            }
        }
    }

    2.2.插入排序

    当插入第i(i>=1)个数据元素时,前面的V[0],V[1],...,V[i-1]已经排好序,这时用V[i]的关键字与前i-1个关键字进行比较,找到位置后将V[i]插入,原来位置上的对象向后顺移。
    技术分享图片
    技术分享图片
    技术分享图片

    template < typename T >
    static void InsertSort(T array[], int len, bool min2max = true)
    {
        for(int i=1; i<len; i++)
        {
            int k = i;
            T e = array[i];
    
            for(int j=i-1; (j>=0) && (min2max ? array[j]>e : array[j]<e); j--)
            {
                array[j+1] = array[j];
                k = j;
            }
    
            if(k != i)
            {
                array[k] = e;
            }
        }
    }

    总结:
    1.选择排序每次选择未排序的最小元素,插入排序每次将第i个元素插入前面i-1个已经排序的序列;
    2.选择排序是不稳定的排序法,插入排序时稳定的排序法。两者的时间复杂度都未O(n^2)

以上是关于数据结构(11)_排序的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

2018.11.29_MySQL约束_总结

如何将列表视图中的数据从一个片段发送到另一个片段

为啥 GraphQL 片段在查询中需要 __typename?

十大排序算法总结(Python3实现)