排序
插入排序
1void insertionsort(elementtype a,intn)2
12 }
由於巢狀迴圈每一次花費n次迭代,因此插入排序時間為o(n2);
逆序:指數組中具有性質ia[j]的序偶(a[i],a[j]);
逆序的個數正好是插入排序執行的交換次數。因為交換兩個不安原序排列的相鄰元素恰好消除乙個逆序,而乙個排過序的陣列沒用逆序。由此可以通過計算排列中的平均逆序數而得出插入逆序平均執行時間的精確的界。
定理:n個互異數的陣列的平均逆序數是n(n-1)/4.
定理:通過交換相鄰元素進行排序的任何演算法平均需要o(n2)的時間。因為初始的平均逆序數是n(n-1)/4=o(n2),而且每次交換只減少乙個逆序,因此需要o(n2)的交換。
希爾排序是一種增量排序方法,通過比較相距一定間隔的元素來工作。
1//使用希爾增量的希爾排序
2void shellsort(elementtype a,intn)3
17 }
使用希爾排序最壞的時間複雜度是o(n2);
堆排序建立n個元素的二叉堆,此時花費o(n)時間。然後我們執行n次的deletemin操作,按照順序,最小的元素離開堆,通過將這些元素記錄到第二個陣列然後將給陣列拷貝回來,得到n個元素的排序,由於每個deletemin的操作的耗時為o(logn),因此總的執行時間o(nlogn)。
該演算法的主要問題是它使用了乙個附加的陣列,因此儲存需求增加了一倍。
避免使用第二個陣列方法是:在每次deletemin之後,堆縮小1,因此位於堆中的最後單元可以用來存放剛剛刪去的元素,使用這種策略之後,該陣列在最後一次deletemin之後,以遞減的順序包含這些元素。
1//堆排序
2#define leftchild(i) (2*(i)+1)//
陣列從0開始,先找左孩子
3void percdown(elementtype a,int i,intn)4
17 a[i]=tmp;18}
19void heapsort(elementtype a,int
n)20
29 }
定理:對n個互異項的隨機排列進行堆排序,所用的比較平均次數為2nlogn-o(nlogn);
歸併排序
合併兩個已排序的表的時間是線性的,因為最多進行了n-1次比較,其中n是元素總數,每次比較都把乙個元素加到最後的序列中,最後的比較除外,它至少新增2個元素;
1//歸併排序
2void msort(elementtype a,elementtype tmparray,int left,int
right)312
}13 mergesoft(elementtype a,int
n)14
24}
25void merge(elementtype a,elementtype tmparray,int lpos,int rpos ,int
rightend)
26
歸併排序是分析遞迴的典型事例
給執行時間寫乙個遞迴關係式:
對於n=1,歸併排序所用時間為常數,記為1;
否則對n個數歸併排序的用時等於完成兩個大小為n/2的遞迴排序所用的時間加上合併的時間(n)。
t(1)=1
t(n)=2t(n/2)+n
解這個遞迴關係式就得所得結果;t(n)=nlogn+n;
雖然歸併排序的執行時間是o(nlogn),但是它很難用於主存排序,問題在於合併兩個排序的表需要額外的附加記憶體,在整個演算法中還要花費時間將資料拷貝到臨時儲存,然後再拷貝回去,其結果放慢了排序速度。
快速排序
是在實踐中最快的已知排序演算法,它的平均執行時間是o(nlogn);該演算法之所以特別快是因為非常精煉的和高度優化的內部迴圈;
選取樞紐元的方法:一種安全的方針是隨機選取樞紐元(效率不高,代價大),二取三數中值分割的方法(實用)
1//快速排序
2 elementtype median3(elementtype a,int left,int
right)314
#define cutoff(3)
15void qsort(elmenttype a,int left,int
right)
1626
while(a[j--]27if(i28 swap(&a[i],&a[j]);
29else
30break;31
}32 swap(&a[i],&a[right-1]);//
樞紐交換
33 qsort(a,left,i-1
);34 qsort(a,i+1
,right);35}
36else
37 insertionsort(a+left,right-left+1);//
元素數量少用插入排序
38 }
注意,將for迴圈改成如下是不能執行的,原因在暈若a[i]=a[j]=privot則會產生乙個死迴圈;
1for(;;)
2
快排演算法分析:
快速排序也是遞迴的,快排的執行時間等於兩個遞迴呼叫的執行時間加上花費在分割上的線性時間;
t(0)=t(1)=1
t(n)=t(i)+t(n-i-1)+cn;
最壞情況之下:t(n)=t(1)+cσi=o(n2);
最好情況之下:t(n)=cnlogn+n=o(nlogn);
證明排序的一般下界:
任何只用到比較的演算法在最壞情況下需要o(nlogn)次比較。即使在平均情況下,只用到比較的排序演算法都需要o(nlogn)次比較。
定理:令t是深度為d的二叉樹,則t最多有2d個樹葉;
→ 具有l片樹葉的二叉樹深度至少logl;
一般排序演算法在最壞情況下的執行時間是o(nlogn),但是在某些特殊情況下以線性時間進行排序也是可以的;比如桶排序,因此排序的時候要廣泛利用資訊,僅僅比較浪費了資訊量;
堆排序要比希爾排序慢,儘管它是乙個帶有明顯緊湊內迴圈的o(nlogn)演算法,對該演算法的深入分析知道,為了移動資料,堆排序要進行2次比較。
資料結構與演算法分析 學習筆記 (4)
雜湊 hash 雜湊是以常數平均時間執行插入,刪除,查詢的技術 需要元素之間比較,排序的資訊,如查詢最大,最小值等等操作不被hash所支援 雜湊表關鍵的是設計雜湊函式,運算簡單並且在單元之間均勻的分配關鍵字,並減少碰撞 1 分離連線雜湊表的型別宣告 2 ifndef hashsep h34 stru...
Python資料結構與演算法筆記(6)
problem solving with algorithms and data structure using python 中文版 7 圖和圖的演算法 頂點 邊 權重 路徑 迴圈 沒有迴圈的圖形稱為非迴圈圖 沒有迴圈的有向圖稱為有向無環圖或dag。圖抽象資料型別如下 實現圖的兩種方式 鄰接矩陣和...
資料結構與演算法分析 leetcode筆記
深度學習知識及資源分享,學習交流,共同進步 leetcode 820 1 題目 給定乙個單詞列表,我們將這個列表編碼成乙個索引字串 s 與乙個索引列表 a。例如,如果這個列表是 time me bell 我們就可以將其表示為 s time bell 和 indexes 0,2,5 對於每乙個索引,我...