研究ノート - ソート

ディレクトリ

 

シンプルシーケンシング

バブルソート

挿入ソート

選択ソート

クイックソート

マージソート

ヒープソート

カウンティングソート

バケットソート

基数ソート


シンプルシーケンシング

バブルソート

隣接する二つの要素毎の比較、大きい(小さい)は、それらの最大ランダムシーケンス(小さい)要素の決定された位置に各パスを作るために、背面に切り換えられます。N全体を実行する時間は、配列、好ましくは、時間複雑性O(N)、平均値、最悪であるO(N ^ 2)を注文し、空間的複雑度はO(1)であり、安定です。

void BubbleSort(Item a[],int n)
{
    for(int i=0;i<n-1;i++)    //执行n趟
        for(int j=0;j<n-1-i;j++)    //第i趟的a[n-i]~a[n]已经排好序,不用重复比较
        {
            if(a[j]>a[j+1])    //以升序排列为例
            {
                swap(a[j],a[j+1]);
            }
        }
}

挿入ソート

全配列が順序付けされるまで、要素の順序付けられたシーケンスと比較して1つによって順不同シーケンス1の最初の要素は、n回の新しい順序付きシーケンスを形成し、正しい位置に挿入されるたびに。この方法では、フロントサブシーケンスがソートされている保証します。好ましくは、平均時間の複雑性O(N)は、O(N ^ 2)の最悪は、空間的複雑度はO(1)であり、安定です。

void InsertSort(Item a[],int n)
{
    for(int i=1;i<n;i++)    //执行n趟,每趟i都指向无序序列的第一个元素
    {
        int j=i-1;    //初始化j,指向有序序列的最后一个元素
        while(j>1&&a[j]>a[i])    //当待插入元素小于当前j指向的元素,则将a[j]往后移一位,为待插入元素腾位置
        {
            a[j]=a[j-1];    //再继续检查前面的所有元素,直到a[j]<a[i],此时j指向的就是需要插入的位置
            j--;
        }
        a[j]=a[i];
    }
        
}

選択ソート

プロモーターがソートされる前に、最も値と第1のスイッチング素子順不同の配列位置からそれぞれランダムな配列を同定、この方法は、順序を保証することができます。時間計算量は好ましくは、最悪の場合、最悪のプローブとして最小に順序付けされるべきかどうか、O(N ^ 2)です。空間の複雑さはO(1)であり、それは例えば、不安定である:最初の交換の後に[58529]、5および2、背面5に第二、及びそれらの相対位置が変更されました。

void SelectSort(Item a[],int n)
{
    for(int i=0;i<n;i++)
    {
        for(int j=i,min_pos=i;j<n;j++)    //a[i]~a[n]是无序区间,初始化最小元素下标为i
        {
            if(a[j]<a[min_pos])    //更新最小元素下标
            {
                min_pos=j;
            }
        }
        swap(a[i],a[min_pos])    //交换无序区间第一个元素与无序区间最小元素的位置
    }
}

クイックソート

各再帰呼び出し要素を決定することができるようにピボット(分割規格)などの配列の要素に、片道再帰呼び出しは、右の左のピボットピボットの値未満では、ピボットの値よりも大きいです最終的な位置。再帰終了条件L> = R、唯一つの要素ソートする、すなわちシーケンスは、前再帰再帰させるため、現在のバックことは明らかです。

void QuickSort(Item a[],int l,int r)
{
    if(l>=r) return;    //序列中只有一个元素时结束递归
    int i=partition(a,l,r);    //获得枢轴的下标
    QuickSort(a,l,i-1);    //对枢轴左半部分调用快排
    QuickSort(a,i+1,r);    //对枢轴右半部分调用快排
}

int partition(Item a[],int l,int r)
{
    //规定一个元素为枢轴,并获得它的最终位置,使在它左边的数都小于它,在它右边的数都大于它
    //让元素a[l]的值作为枢轴值
    int x=a[l];
    int i=l,j=r;
    while(i!=j)
    {
        while(j>i&&a[j]>=x) j--;
        if(j>i)    //此时退出while是因为j指向比枢轴值小的数
        {
            a[i]=a[j];    //直接覆盖i指向的元素,放在枢轴左边
            i++;
        }
        while(j<i&&a[i]<x) i++;
        if(j>i)    //此时i指向比枢轴值大的数
        {
            a[j]=a[i];    //放在枢轴右边
            j--;
        }
        //由于第一次覆盖的元素就是枢轴,是我们已知的,所以直接覆盖不会丢失数据。
        //而在这之后被覆盖的元素都是无关紧要的,因为它的值在上一步已经去了它该去的位置了。
        //执行到最后,只有枢轴值x不知道它该去的位置在哪里,显然,就是i=j的位置。
    }
    a[i]=x;
}

マージソート

シーケンス内の唯一の要素、再帰の終了があるまで順次二つの末端の配列に続く、それぞれ、ほぼ同じ大きさの左右両端部に分割するソート列ソート再帰的にマージします。各ラウンド再帰の終了時に、エリア両側を別々に順序付けられます。このとき、良好な吐出を有し、元の長さの配列に結合するまで、ワークエリアに、前再帰へ戻る続け、1つのシーケンスに二つの配列を命じました。最後に、作業領域との完全な配列行良好な配列がソートされる要素の元の配列を更新します。

void MergeSort(Item a[],int l,int r)
{
    int mid=(l+r)/2;
    if(r<=l) return;
    MergeSort(a,l,mid);
    MergeSort(a,mid+1,r);
    MergeAB(a,b,l,m,r);
}


void MergeAB(Item a[],Item b[],int l,int m,int r)
{
    int i=l,j=mid+1,k=0;    //指针指向两个子序列的第一个元素
    while(i<=mid&&j<=r)    //若未超出所指示的子序列,则将较小值存入工作区b
    {
        if(a[i]<a[j]) b[k++]=a[i];
        else b[k++]=a[j]; 
    }
    if(i>m)    //若i先超出所子序列,则只需把j还未遍历的数组全部赋给工作区b
    {
        while(j<=r) b[k++]=a[j++];
    }
    else       //若i先超出所子序列,则只需把j还未遍历的数组全部赋给工作区b
        while(i<=mid) b[k++]=a[i++];
    for(int i=l;i<=r;i++)
    {
        a[i]=b[i];    //再把工作区b里的序列复制到数组a去
    }
}

 

ヒープソート

鍵ストレージが1で開始しなければならない配列に完全二分木の構造的特徴によってソートされる配列は、私は子供を残した配列要素は、右の子は2I + 1であり、2Iです。積層後に構築された後、配列の最後の要素(すなわち、完全二分木と、最小出力電流(大)の要素を、調整されたスタックにn回対応し、ソートされるn個の要素の配列をソートします最後に、リーフノード)再調整スタックを引き起こし、スタック要素の上部を置換。

void Sift(Item R[],int low,int high)
{
    //这是一个自上而下的堆调整
    int i=low,j=2*i;    //j是i的左孩子
    int temp=R[i];
    while(j<=high)
    {
        if(j<high&&R[j]<R[j+1])    //右孩子更大
        {
            j++;    //j指向右孩子
        }
        /*以上操作使j指向左右孩子中较大的一个*/
        if(temp<R[j])
        {
            R[i]=R[j];
            i=j;    //i下降,不用管另一个孩子,因为R[i]与R[j]的交换没有影响到另一个孩子及其子树
            j=i*2;    //j仍指向i的左孩子
        }
        else break;
    }
    R[i]=temp;    //被调整结点的值放入最终位置
    //最终要找到一个R[j]不大于当前根节点R[low]的地方将temp放进去,如果j走到最后都没有这样的位置,说明R[low]就是最大的,就把一开始放在temp里的值再还给R[low]
}

/*堆排序函数*/
void HeapSort(Item R[],int n)
{
    for(int i=n/2;i>=1;i--)    //从最后一个叶子结点的父节点开始,自下而上,自右向左调整,每次以结点i为堆的根结点
        Sift(R,i,n);
    /*上面是堆的初始化,下面是每一轮最值的输出和后续的调整*/
    for(int i=n;i>=2;i--)    //从最后一个叶子结点开始,自下而上,自右向左,每次用最后一个叶子结点替换堆顶结点,从而引起新一轮的调整
    {
        temp=R[1];
        R[1]=R[i];
        R[i]=temp;
        Sift(R,1,i-1);    //开始新的一轮调整是从下到下,从左到右的,由于第i个元素已经有序,所以只需要调整到第i-1个元素
    }
}

言い換えれば、親ノードからソート・ヒープ・ソート処理が下から上に、右から左へ、最後のリーフノードの開始である左から、ノードの順序は、その後、上から下へ、ツリーのルートでありますそれぞれの子のために、ツリー全体の完全なバイナリ・ツリーは大(小)ヒープルートで満たされるまで、右の調整。出力スタックの上部後、最後のリーフノード接合あるいはスタックトップと、その後スタックは、上から下にスタックの最上部から、調整する必要があり、この時間を大(小)ヒープルート特性を満足しないことがあり、調整するために、左から右に、

カウンティングソート

シーケンスの最大値maxと最小値minを見つけ、配列DIST空間Cを開放するようにそれらの長さの差、トラバース配列A [i]の各訪問、Cの実装[分+ I] ++、最後に、オーダーの長さ長さ()の配列にC [分+ I]番目のA [i]のに移動します。

バケットソート

次いで、第一槽ベース10、浴槽への各元素の十の位の値を、次に、適用に応じて、そのようなソートなどのバレル要素の2ビットは、各バケットの内部をソートし、ソート順序付けられたシーケンスを取得するために一緒にステッチ。

基数ソート

実際にはバケットソートと同じ程度、思考が、唯一、ベンチマークとしてソートされた最初のビットをソートする整数を、ソート結果が偽につなぎ合わせ、ソート結果が一緒にステッチ、10のベンチマークとして、このシーケンスの種類を順序を命じました本当の順序付けられたシーケンスを取得します。

 

ピクチャー転載から:https://www.jianshu.com/p/134a0eed5e3a

                      https://www.jianshu.com/p/0807c3557dc2

                      https://www.jianshu.com/p/1d04c34defd0

公開された35元の記事 ウォンの賞賛2 ビュー1388

おすすめ

転載: blog.csdn.net/weixin_41001497/article/details/102489066