排序方法分狠多,可分為外部排序和內部排序。內部排序可分為:插入排序、交換排序、歸併排序、堆排序、基數排序。分析各種排序演算法的優劣有演算法
時間複雜度和執行演算法所需的附加空間。
1. 插入排序
<>
演算法中引進的附加a[0]稱監視哨或哨兵。哨兵有兩個作用 1:在進入查詢(插入位置)迴圈之前,它儲存了a[i]的副本,保證不致於因記錄後移而丟失a[i]的內容。2:在查詢迴圈中監視下標變數j是否越界,一旦越界(j=0),則迴圈判定條件不成立使的查詢迴圈結束,從而避免了在迴圈內的每一次均要檢測j是否越界。
#include #include #define n 5
void insert(int a)
}}void shellsort(int a)
while(increment > 1);
}int main(void)
關於希爾排序的一些思考:
當把shellpass()函式換成下面的函式時 ------------>>>>>>>>>>>>>>
void shallpass_new(int a, int d, int len)
while(j>0 && a[0] < a[j-d]);
a[j] = a[0];}}
}
輸出結果是不對的,為什麼呢?我想是陣列的越界問題。因為在shallpass_new()函式中,當j -= d後還沒有越出了陣列的範圍,而j在減去d越出陣列時,此時j>0是成立的,並且有可能a[0] < a[j-d]也是成立的,因為陣列前面記憶體中所存放的資料也可能是大於a[0]的,在此之後在進行資料的操作時,就會出現問題了。而在shallpass()函式中,就不會出現這樣的問題啦。^_^
2. 交換排序
<>
氣泡排序時最簡單的排序方法,基本思想是將待排序的元素看作是豎著的氣泡,較小的氣泡比較輕,會自然的上移。
void bubblesort(int a, int n)}}
}
<>
快速排序實際上是氣泡排序的集中改進,基本思想是在帶排序的n個記錄中任取乙個記錄(如第乙個記錄),以該記錄的值為基準,將所有的記錄分為兩組(一般都是無序的),使的第一組的值都小於或等於該記錄,第二組的值都大於或則等於該記錄,然後把該記錄排在這兩組的中間,(這也是該記錄的最終位置),這樣成為一次快速排序。對多分成的這兩組分別進行快速排序,知道所有記錄都排在合適的位置上為止。
#include #include #define n 10
void quicksort(int a, int left, int right)
void mergesort(int a, int low, int high)
}int main(void)
; int i;
mergesort(a, 0, 9);
for(i = 0; i < 10; i++)
printf("%d ", a[i]);
return 0;
}
4.選擇排序
<>
每一趟從待排序的資料元素
中選出最小(或最大)的乙個元素,順序放在已排好序的數列的最後,直到全部待排序的資料元素排完。選擇排序
是不穩定的排序方法。
void choicesort(int a, int n)}}
5.堆排序
<>
以下幾段話和是引用一位網友的部落格中的內容:
記得在學習資料結構的時候一味的想用**實現演算法,重視的是寫出來的**有乙個正確的輸入,然後有乙個正確的輸出,那麼就很滿足了。從網上看了許多的**,看了之後貌似懂了,自己寫完之後也正確了,但是不久之後就忘了,因為大腦在回憶的時候,只依稀記得**中的部分,那麼的模糊,根本不能再次寫出正確的**,也許在第一次寫的時候是因為參考了別人的**,看過之後大腦可以進行短暫的高畫質晰記憶,於是欺騙了我,以為自己寫出來的,滿足了成就感。可是**是計算機識別的,而我們更喜歡文字,影象。所以我們在學習演算法的時候要注重演算法的原理以及演算法的分析,用文字,影象表達出來,然後當需要用的時候再將文字轉換為**。記憶分為三個步驟:編碼,儲存和檢索,就以學習為例,先理解知識,再歸納知識,最後鞏固知識,為了以後的應用而方便檢索知識。
說明:堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即a[parent[i]] >= a[i]。在陣列的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
既然是堆排序,自然需要先建立乙個堆,而建堆的核心內容是調整堆,使二叉樹滿足堆的定義(每個節點的值都不大於其父節點的值)。調堆的過程應該從最後乙個非葉子節點開始,假設有陣列a = 。那麼調堆的過程如下圖,陣列下標從0開始,a[3] = 5開始。分別與左孩子和右孩子比較大小,如果a[3]最大,則不用調整,否則和孩子中的值最大的乙個交換位置,在圖1中是a[7] > a[3] > a[8],所以a[3]與a[7]對換,從圖1.1轉到圖1.2。
所以建堆的過程就是
for ( i = headlen/2; i >= 0; i++)
2:
3:調堆:如果初始陣列是非降序排序,那麼就不需要調堆,直接就滿足堆的定義,此為最好情況,執行時間為θ(1);如果初始陣列是如圖1.5,只有a[0] = 1不滿足堆的定義,經過與子節點的比較調整到圖1.6,但是圖1.6仍然不滿足堆的定義,所以要遞迴調整,一直到滿足堆的定義或者到堆底為止。如果遞迴調堆到堆底才結束,那麼是最壞情況,執行時間為o(h) (h為需要調整的節點的高度,堆底高度為0,堆頂高度為floor(logn) )。do adjustheap(a, heaplen, i)
建堆完成之後,堆如圖1.7是個大根堆。將a[0] = 8 與 a[heaplen-1]交換,然後heaplen減一,如圖2.1,然後adjustheap(a, heaplen-1, 0),如圖2.2。如此交換堆的第乙個元
素和堆的最後乙個元素,然後堆的大小heaplen減一,對堆的大小為heaplen的堆進行調堆,如此迴圈,直到heaplen == 1時停止,最後得出結果如圖3。
輸入:陣列a,堆的長度hlen,以及需要調整的節點i
功能:調堆
*/void adjustheap(int a, int hlen, int i)
if (right < hlen && a[largest] < a[right])
if (i != largest) //如果最大值不是父節點
else
break;
}}/*
輸入:陣列a,堆的大小hlen
功能:建堆
*/void buildheap(int a, int hlen)}/*
輸入:陣列a,待排序陣列的大小alen
功能:堆排序
*/void heapsort(int a, int alen)
}int main(void)
; int i;
heapsort(a, 10);
for(i = 0; i < 10; i++)
printf("%d ", a[i]);
return 0;
}
排序演算法學習
一直都想把排序和搜尋類的演算法總結一下,一直拖著沒寫,主要是太懶了,現在決定還是要再好好學習下這些基本的演算法。畢竟基礎真的是很重要。好了現在開始學習第乙個排序演算法 插入排序 我記得插入排序在我們以前的資料結構教程上是第乙個介紹的 插入排序 聽這個排序名字就是將乙個什麼數要插入到某個地方,不錯,他...
排序演算法學習
1.氣泡排序 using system using system.collections.generic using system.linq using system.text using system.threading.tasks namespace 排序演算法練習 從小排序 public ov...
排序演算法學習
快速排序演算法 通過一趟排序將資料分成兩部分 其中一部分的資料要比 另外一部分小或大 利用遞迴進行 直至資料有序 演算法步驟 1.定義兩個指標分別指向低位和高位 2.將陣列第乙個元素作為基數 3.從後往前遍歷 high 直至找到第乙個小於key的值 4.從前往後遍歷 low 直至找到第乙個大於key...