插入排序
o(n2),基本思路就是玩撲克牌的時候,從牌堆裡摸牌放到手上的思路.
#include
#include
#include
#include
#include
#include
const
int m = 1000;
const
int n = 1000;
template
void insertsort(const iterator &a, const iterator &b)
i -- ;
q--;}}
}void producedata(std::vector
&data)
}template
void checkvalid(iterator b, iterator e)
if(comparator()(*t,*b))
b++;
}}template
class smaller
};int main()
歸併排序
//o(nlgn),需要額外空間
template
void merge(iterator s, iterator p, iterator e)
else
tmp++;
}if(i< s1)
if(j < s2)
delete l;
delete r;
}template
void mergesort(iterator s, iterator e)
}int main()
; mergesort(a, a+7);
std::copy(a,a+7, std::ostream_iterator(std::cout, " "));
std::cout
<< std::endl;
}
快速排序o(nlgn)
int randomnumber(int p, int q)
template
iterator partition(iterator s, iterator e, typename
std::iterator_traits::value_type n)//返回乙個序列,使得大於n的在左邊,小於n的在右邊
return p;
}template
iterator randomizedpartition(iterator s, iterator e)//隨機抽取乙個元素,作為主元,用它來重新劃分序列
template
void quicksort(iterator s, iterator e)
}int main()
; quicksort(a,a+sizeof(a)/sizeof(int));
std::copy(a,a+sizeof(a)/sizeof(int), std::ostream_iterator(std::cout, " "));
std::cout
<< std::endl;
}
歸併和快排的**有點相似,都是利用分治策略來進行問題的求解的.
分治策略大體上分為3步,即分解, 解決, 合併
歸併排序和快排也是按照這三個步驟進行的,不過二者有點差異.歸併排序在分解的時候,不做任何處理,問題的分解沒有利用到原問題的資訊,一路分解到子問題規模足夠小(也就是剩下乙個元素的時候),乙個元素預設有序,因此子問題直接解決,最後呼叫合併有序序列的方法將結果進行合併.
快速排序在分解的時候,就進行了對問題的解決(對序列按主元進行了重新劃分),問題分解的時候利用到了原問題的資訊.
歸併排序是按照自底向上的順序進行排序
快速排序是按照自頂向下的順序進行排序
堆排序
o(nlgn)
首先明白堆的性質,操作物件是個陣列,可被視為乙個幾乎完全的二叉樹.
對於所有非根節點,當a[parent[i]] >= a[i],視為最大堆
a[parent[i]] <= a[i], 視為最小堆.
堆排序首先需要建立堆,建立堆的意思就是調整陣列的元素位置,使得陣列的元素符合堆的樣子,即對陣列a, 有a[parent[i]] >= a[i] 或者a[parent[i]] <= a[i].
調整的方式是自下而上,就從所有的非葉子節點開始調整,保證從非葉子節點開始往下都是堆有序的(即所有非葉子節點的子節點i, 滿足a[parent[i]] >= a[i] or a[parent[i]] <= a[i])
堆排序就更簡單了,將堆頂元素和陣列最後乙個元素交換,然後再調整堆頂節點,使得交換後的堆恢復堆有序.不斷交換直至完全有序為止.
template
void downheap(iterator s, int i, int n)
}if(2*i +2
< n)
}if(min != *p)
}template
void upheap(iterator s, int i)}}
}template
void makeheap(iterator s, iterator e)
}template
void heapsort(iterator s, iterator e)
}int main()
; makeheap(a,a+7);
heapsort(a,a+7);
std::copy(a,a+sizeof(a)/sizeof(int), std::ostream_iterator(std::cout, " "));
std::cout
<< std::endl;
}
優先佇列
這東西可以被理解成乙個包裹了heap 的殼子,它的核心就是乙個heap. 不過它可以限定了內建heap的大小.定義了出隊和入隊操作. 出隊和入隊事實上就是堆的插入和刪除操作
這玩意再統計topk裡面很有用.
具體如下,首先弄乙個最小堆
堆頂元素是最小值.
當讀入元素小於k時,就入隊.
當讀入元素大於k時,比較該元素與堆頂元素大小.如果比堆頂小,捨棄;如果大於堆頂元素,刪除堆頂元素,將該元素入隊
template
class prioqueue
void enqueue(t e)
t deque()
t top()
void print()
};int main()
; makeheap(a,a+3);
std::copy(a,a+sizeof(a)/sizeof(int), std::ostream_iterator(std::cout, " "));
std::cout
<< std::endl;
heapsort(a,a+3);
std::copy(a,a+sizeof(a)/sizeof(int), std::ostream_iterator(std::cout, " "));
std::cout
<< std::endl;
prioqueue q;
q.enqueue(kk);
q.print();
q.dequeue();
q.print();
}
//stl定義了優先佇列的結構,這裡簡單列一下用法
struct node
};struct nodecmp
};int main()
{ std::priority_queuestd::vector
, nodecmp> m;
m.push(node(5, "ss"));
m.push(node(3, "aa"));
m.push(node(1, "bb"));
}
基於比較的排序次數最壞情況下至少需要nlgn次比較.
假設比較1,2,3. 我們以二叉樹分支表示,頂點位置記成1:2(拿1和2比較),小於進左邊分支,大於進右邊分支.這樣葉子節點就是最終能到3個元素的全排列.全排列是n的階乘.高度h 的滿二叉樹最多有2的h次方個葉子.所以 n!<=2的h次方(公式). 因為任何一次從頂點到根的路徑就是乙個排序過程. 所以最壞排序情況肯定在其中一條路徑上.所做的比較次數 也就是h.
n!<=2的h次方,兩邊取對數h>=lg(n!)>=nlgn.
穩定排序, 假設待排序的序列有兩個相同的元素a,b, 其中a,b的值是一樣的,排序前a 在b前面,排序後a 還在b的前面,則為穩定排序,否則為不穩定排序.
插入排序,歸併排序和堆排序都是穩定排序.快排則不是穩定排序
排序演算法系列之氣泡排序
核心思想 氣泡排序是一種典型的 交換排序 通過比較相鄰元素大小來決定是否交換位置 如上圖所示,以一組資料 為例,進行氣泡排序的演算法演示 氣泡排序 c void swap int a,int b void bubblesort vector vi 演算法改進說明 1,對於是否已經是有序排列進行判斷 ...
排序演算法系列
概述 概念 排序是計算機內經常進行的一種操作,其目的是將一組 無序 的記錄序列調整為 有序 的記錄序列。排序分為內部排序和外部排序。若整個排序過程不需要訪問外存便能完成,則稱此類排序問題為內部排序。反之,若參加排序的記錄數量很大,整個序列的排序過程不可能在記憶體中完成,則稱此類排序問題為外部排序。排...
排序演算法系列之合併排序
歸併排序 merge sort,合併排序 是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法 divide and conquer 的乙個非常典型的應用。歸併操作 merge 指的是將兩個已經排序的序列合併成乙個序列的操作,歸併排序演算法依賴歸併操作。歸併操作的過程如下 申請空間,使其大...