排序算法學習

前言

參考文章:http://blog.csdn.net/hguisu/article/details/7776068 

文章中對算法的解釋非常詳細,這裏只做個人總結和部分算法代碼 使用的平臺爲unity,用c#編寫 ,其中代碼中涉及的數學方法爲unity封裝後的方法


插入排序


直接插入排序


    /// <summary>
    /// 直接插入排序 (使用List結構)
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    List<int> Sort_Zhijiecharu(List<int> data) 
    {
        //從小到大
        for (int i = 1; i < data.Count; i++)
        {
            int temp = data[i];
            int j = i - 1;
            if (data[i]< data[i-1])// 如果有調整需要
            {
                while (temp < data[j])//向前遍歷,一直找到比當前元素小的數的下標
                {
                    j--;
                    if (j < 0) break;//防止下標越界
                }
                data.RemoveAt(i);
                data.Insert(j+1, temp);//將當前元素,插入到後面
            } 
        }
        return data;
    }


希爾排序


    /// <summary>
    /// 希爾排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_Sell(int[] data) 
    {
        int dk = data.Length;
        while (true)
        {
            dk = Mathf.CeilToInt(dk / 2f);
            data = Sort_Sell_Zhijiecharu(data, dk);
            if (dk == 1) break;
        }
        return data;
    }

    /// <summary>
    /// 希爾排序中使用到的直接插入
    /// </summary>
    /// <param name="data"></param>
    /// <param name="dk">下標的增量 直接插入排序dk=1</param>
    /// <returns></returns>
    int[] Sort_Sell_Zhijiecharu(int[] data,int dk)
    {
        //從小到大
        int temp = 0;
        for (int x = 0; x < dk; x++)//遍歷 通過dk分成的子序列
        {
            for (int i = x + dk; i < data.Length; i += dk)//遍歷子序列
            {
                int j = i - dk;
                temp = data[i];
                for (; j >= 0 && temp < data[j]; j -= dk)//向前遍歷 如果前面元素>當前元素 
                {
                    data[j + dk] = data[j];//前面元素後移
                }
                data[j + dk] = temp;//將當前元素插入到目標位置
            }
        }
        return data;
    }


選擇排序


簡單選擇排序


    /// <summary>
    /// 簡單排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_Jiandan(int[] data) 
    {
        int pos = 0;
        int temp = 0;
        for (int i = 0; i < data.Length; i++)
        {
            temp = data[i];
            pos = i;
            //遍歷後面的數據,從中找出一個最小的
            for (int j = i+1; j < data.Length; j++)
            {
                if (data[j]<temp)
                {
                    temp = data[j];
                    pos = j;
                }
            }
            //交換位置
            data[pos] = data[i];
            data[i] = temp;
        }
        return data;
    }


堆排序


    /// <summary>
    /// 調整爲大頂堆(或 小頂堆)
    /// </summary>
    /// <param name="H">數組</param>
    /// <param name="parent">父節點</param>
    /// <param name="length">數組長度</param>
    void HeapAdjust(int[] H, int parent, int length)
    {
        //構建一個大頂堆,即堆頂爲最大元素
        int tmp = H[parent];
        int child = 2 * parent + 1; //左孩子結點的位置。(i+1 爲當前調整結點的右孩子結點的位置)  
        while (child < length)//經過循環,保證以H[parent]爲根結點的子數爲一個大頂堆
        {
            if (child + 1 < length && H[child] < H[child + 1])
            {   //如果右孩子大於左孩子(找到比當前待調整結點大的孩子結點)  
                child++;
            }
            if (H[parent] < H[child])
            {   //如果較大的子結點大於父結點  
                H[parent] = H[child]; // 那麼把較大的子結點往上移動,替換它的父結點  
                parent = child;       // 重新設置parent,即待調整的下一個結點的位置  
                child = 2 * parent + 1;
            }
            else
            {   //如果當前待調整結點大於它的左右孩子,則不需要調整,直接退出  
                break;
            }
            H[parent] = tmp;//當前待調整的結點放到比其大的孩子結點位置上  
        }
    }

    /// <summary>
    /// 創建初始堆
    /// </summary>
    /// <param name="H"></param>
    /// <param name="length"></param>
    void BuildingHeap(int[] H, int length)
    {
        //最後一個有孩子的節點的位置 i=  (length -1) / 2  
        for (int i = (length - 1) / 2; i >= 0; --i)
        {   
            HeapAdjust(H, i, length);
        }      
    }

    /// <summary>
    /// 堆排序
    /// </summary>
    /// <param name="H"></param>
    /// <param name="length"></param>
    void Sort_Heap(int[] H, int length)
    {
        //初始堆  
        BuildingHeap(H, length);
        //從最後一個元素開始對序列進行調整  
        for (int i = length - 1; i > 0; --i)
        {
            //交換堆頂元素H[0]和堆中最後一個元素  
            int temp = H[i]; H[i] = H[0]; H[0] = temp;
            //每次交換堆頂元素和堆中最後一個元素之後,都要對堆進行調整  
            HeapAdjust(H, 0, i);
        }
    }


交換排序


冒泡排序


    /// <summary>
    /// 冒泡排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_MaoPao(int[] data)
    {
        //從小到大排序
        DateTime start = DateTime.Now;
        int count = data.Length;
        //冒泡 
        for (int i = 0; i < count - 1; i++)
        {
            for (int j = 0; j < count - 1 - i; j++)
            {
                if (data[j] > data[j + 1])
                {
                    int temp = data[j + 1];
                    data[j + 1] = data[j];
                    data[j] = temp;
                }
            }
        }
        TimeSpan dur = DateTime.Now - start;
        print(dur.Milliseconds);
        return data;
    }


快速排序


    /// <summary>
    /// 快速排序
    /// </summary>
    /// <param name="a"></param>
    /// <param name="low"></param>
    /// <param name="high"></param>
    void Sort_Quick(int[] a, int low, int high)
    {
        if (low < high)
        {
            int privotLoc = Partition(a, low, high);  //將表一分爲二  
            Sort_Quick(a, low, privotLoc - 1);        //遞歸對低子表遞歸排序  
            Sort_Quick(a, privotLoc + 1, high);       //遞歸對高子表遞歸排序  
        }
    }

    int Partition(int[] a, int low, int high)
    {
        int privotKey = a[low];//基準元素  
        int temp = 0;
        while (low < high)
        {
            //從表的兩端交替地向中間掃描  
            while (low < high && a[high] >= privotKey) --high;//從high 所指位置向前搜索,至多到low+1 位置。將比基準元素小的交換到低端  
            //位置互換
            temp = a[high];
            a[high] = a[low];
            a[low] = temp;
            while (low < high && a[low] <= privotKey) ++low;
            //位置互換
            temp = a[high];
            a[high] = a[low];
            a[low] = temp;
        }
        return low;
    }


時間複雜度




穩定性


排序算法的穩定性:若待排序的序列中,存在多個具有相同關鍵字的記錄,經過排序, 這些記錄的相對次序保持不變,則稱該算法是穩定的

若經排序後,記錄的相對次序發生了改變,則稱該算法是不穩定的。 

穩定性的好處:排序算法如果是穩定的,那麼從一個鍵上排序,然後再從另一個鍵上排序,第一個鍵排序的結果可以爲第二個鍵排序所用。

基數排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,如果排序算法穩定,可以避免多餘的比較


如何選擇排序算法


排序算法簡單的講分爲兩種 空間換時間,時間換空間

根據數據量的多少,數據量的大小,排序速度要求,內存空間大小,穩定性要求,

具體內容 上述文章最後有講,比較詳細



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章