sift演算法代碼
❶ 排序法都有哪些
一、插入排序(InsertionSort)
1.基本思想:
每次將一個待排序的數據元素,插入到前面已經排好序的數列中的適當位置,使數列依然有序;直到待排序數據元素全部插入完為止。
2.排序過程:
【示例】:
[初始關鍵字][49]38659776132749
J=2(38)[3849]659776132749
J=3(65)[384965]9776132749
J=4(97)[38496597]76132749
J=5(76)[3849657697]132749
J=6(13)[133849657697]2749
J=7(27)[13273849657697]49
J=8(49)[1327384949657697]
- ProcereInsertSort(VarR:FileType);
- //對R[1..N]按遞增序進行插入排序,R[0]是監視哨//
- Begin
- forI:=2ToNDo//依次插入R[2],...,R[n]//
- begin
- R[0]:=R;J:=I-1;
- WhileR[0]<R[J]Do//查找R的插入位置//
- begin
- R[J+1]:=R[J];//將大於R的元素後移//
- J:=J-1
- end
- R[J+1]:=R[0];//插入R//
- end
- End;//InsertSort//
1.基本思想:
每一趟從待排序的數據元素中選出最小(或最大)的一個元素,順序放在已排好序的數列的最後,直到全部待排序的數據元素排完。
2.排序過程:
【示例】:
初始關鍵字[4938659776132749]
第一趟排序後13[38659776492749]
第二趟排序後1327[659776493849]
第三趟排序後132738[9776496549]
第四趟排序後13273849[49976576]
第五趟排序後1327384949[979776]
第六趟排序後132738494976[7697]
第七趟排序後13273849497676[97]
最後排序結果1327384949767697
- ProcereSelectSort(VarR:FileType);//對R[1..N]進行直接選擇排序//
- Begin
- forI:=1ToN-1Do//做N-1趟選擇排序//
- begin
- K:=I;
- ForJ:=I+1ToNDo//在當前無序區R[I..N]中選最小的元素R[K]//
- begin
- IfR[J]<R[K]ThenK:=J
- end;
- IfK<>IThen//交換R和R[K]//
- beginTemp:=R;R:=R[K];R[K]:=Temp;end;
- end
- End;//SelectSort//
1.基本思想:
兩兩比較待排序數據元素的大小,發現兩個數據元素的次序相反時即進行交換,直到沒有反序的數據元素為止。
2.排序過程:
設想被排序的數組R[1..N]垂直豎立,將每個數據元素看作有重量的氣泡,根據輕氣泡不能在重氣泡之下的原則,從下往上掃描數組R,凡掃描到違反本原則的輕氣泡,就使其向上"漂浮",如此反復進行,直至最後任何兩個氣泡都是輕者在上,重者在下為止。
【示例】:
4913131313131313
3849272727272727
6538493838383838
9765384949494949
7697654949494949
1376976565656565
2727769776767676
4949497697979797
- ProcereBubbleSort(VarR:FileType)//從下往上掃描的起泡排序//
- Begin
- ForI:=1ToN-1Do//做N-1趟排序//
- begin
- NoSwap:=True;//置未排序的標志//
- ForJ:=N-1DownTo1Do//從底部往上掃描//
- begin
- IfR[J+1]<R[J]Then//交換元素//
- begin
- Temp:=R[J+1];R[J+1:=R[J];R[J]:=Temp;
- NoSwap:=False
- end;
- end;
- IfNoSwapThenReturn//本趟排序中未發生交換,則終止演算法//
- end
- End;//BubbleSort//
1.基本思想:
在當前無序區R[1..H]中任取一個數據元素作為比較的"基準"(不妨記為X),用此基準將當前無序區劃分為左右兩個較小的無序區:R[1..I-1]和R[I+1..H],且左邊的無序子區中數據元素均小於等於基準元素,右邊的無序子區中數據元素均大於等於基準元素,而基準X則位於最終排序的位置上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),當R[1..I-1]和R[I+1..H]均非空時,分別對它們進行上述的劃分過程,直至所有無序子區中的數據元素均已排序為止。
2.排序過程:
【示例】:
初始關鍵字[4938659776132749]
第一次交換後
[2738659776134949]
第二次交換後
[2738499776136549]
J向左掃描,位置不變,第三次交換後
[2738139776496549]
I向右掃描,位置不變,第四次交換後
[2738134976976549]
J向左掃描
[2738134976976549]
(一次劃分過程)
初始關鍵字
[4938659776132749]
一趟排序之後
[273813]49[76976549]
二趟排序之後
[13]27[38]49[4965]76[97]
三趟排序之後1327384949[65]7697
最後的排序結果1327384949657697
各趟排序之後的狀態
- ProcereParttion(VarR:FileType;L,H:Integer;VarI:Integer);
- //對無序區R[1,H]做劃分,I給以出本次劃分後已被定位的基準元素的位置//
- Begin
- I:=1;J:=H;X:=R;//初始化,X為基準//
- Repeat
- While(R[J]>=X)And(I<J)Do
- begin
- J:=J-1//從右向左掃描,查找第1個小於X的元素//
- IfI<JThen//已找到R[J]〈X//
- begin
- R:=R[J];//相當於交換R和R[J]//
- I:=I+1
- end;
- While(R<=X)And(I<J)Do
- I:=I+1//從左向右掃描,查找第1個大於X的元素///
- end;
- IfI<JThen//已找到R>X//
- begin R[J]:=R;//相當於交換R和R[J]//
- J:=J-1
- end
- UntilI=J;
- R:=X//基準X已被最終定位//
- End;//Parttion//
- ProcereQuickSort(VarR:FileType;S,T:Integer);//對R[S..T]快速排序//
- Begin
- IfS<TThen//當R[S..T]為空或只有一個元素是無需排序//
- begin
- Partion(R,S,T,I);//對R[S..T]做劃分//
- QuickSort(R,S,I-1);//遞歸處理左區間R[S,I-1]//
- QuickSort(R,I+1,T);//遞歸處理右區間R[I+1..T]//
- end;
- End;//QuickSort//
1.基本思想:
堆排序是一樹形選擇排序,在排序過程中,將R[1..N]看成是一顆完全二叉樹的順序存儲結構,利用完全二叉樹中雙親結點和孩子結點之間的內在關系來選擇最小的元素。
2.堆的定義:N個元素的序列K1,K2,K3,...,Kn.稱為堆,當且僅當該序列滿足特性:
Ki≤K2iKi≤K2i+1(1≤I≤[N/2])
堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉子結點的關鍵字均大於等於其孩子結點的關鍵字。例如序列10,15,56,25,30,70就是一個堆,它對應的完全二叉樹如上圖所示。這種堆中根結點(稱為堆頂)的關鍵字最小,我們把它稱為小根堆。反之,若完全二叉樹中任一非葉子結點的關鍵字均大於等於其孩子的關鍵字,則稱之為大根堆。
3.排序過程:
堆排序正是利用小根堆(或大根堆)來選取當前無序區中關鍵字小(或最大)的記錄實現排序的。我們不妨利用大根堆來排序。每一趟排序的基本操作是:將當前無序區調整為一個大根堆,選取關鍵字最大的堆頂記錄,將它和無序區中的最後一個記錄交換。這樣,正好和直接選擇排序相反,有序區是在原記錄區的尾部形成並逐步向前擴大到整個記錄區。
【示例】:對關鍵字序列42,13,91,23,24,16,05,88建堆
- ProcereSift(VarR:FileType;I,M:Integer);
- //在數組R[I..M]中調用R,使得以它為完全二叉樹構成堆。事先已知其左、右子樹(2I+1<=M時)均是堆//
- Begin
- X:=R;J:=2*I;//若J<=M,R[J]是R的左孩子//
- WhileJ<=MDo//若當前被調整結點R有左孩子R[J]//
- begin
- If(J<M)AndR[J].Key<R[J+1].KeyThen
- J:=J+1//令J指向關鍵字較大的右孩子//
- //J指向R的左、右孩子中關鍵字較大者//
- IfX.Key<R[J].KeyThen//孩子結點關鍵字較大//
- begin
- R:=R[J];//將R[J]換到雙親位置上//
- I:=J;J:=2*I//繼續以R[J]為當前被調整結點往下層調整//
- end;
- Else
- Exit//調整完畢,退出循環//
- end
- R:=X;//將最初被調整的結點放入正確位置//
- End;//Sift//
- ProcereHeapSort(VarR:FileType);//對R[1..N]進行堆排序//
- Begin
- ForI:=NDivDownto1Do//建立初始堆//
- Sift(R,I,N)
- ForI:=NDownto2do//進行N-1趟排序//
- begin
- T:=R[1];R[1]:=R;R:=T;//將當前堆頂記錄和堆中最後一個記錄交換//
- Sift(R,1,I-1)//將R[1..I-1]重成堆//
- end
- End;//HeapSort//
1.選取排序方法需要考慮的因素:
(1)待排序的元素數目n;
(2)元素本身信息量的大小;
(3)關鍵字的結構及其分布情況;
(4)語言工具的條件,輔助空間的大小等。
2.小結:
(1)若n較小(n<=50),則可以採用直接插入排序或直接選擇排序。由於直接插入排序所需的記錄移動操作較直接選擇排序多,因而當記錄本身信息量較大時,用直接選擇排序較好。
(2)若文件的初始狀態已按關鍵字基本有序,則選用直接插入或冒泡排序為宜。
(3)若n較大,則應採用時間復雜度為O(nlog2n)的排序方法:快速排序、堆排序或歸並排序。
快速排序是目前基於比較的內部排序法中被認為是最好的方法。
(4)在基於比較排序方法中,每次比較兩個關鍵字的大小之後,僅僅出現兩種可能的轉移,因此可以用一棵二叉樹來描述比較判定過程,由此可以證明:當文件的n個關鍵字隨機分布時,任何藉助於"比較"的排序演算法,至少需要O(nlog2n)的時間。
這句話很重要它告訴我們自己寫的演算法是有改進到最優當然沒有必要一直追求最優
(5)當記錄本身信息量較大時,為避免耗費大量時間移動記錄,可以用鏈表作為存儲結構。
❷ java面試題 很急 謝謝
2, 歸並排序(merge sort)體現了分治的思想,即將一個待排序數組分為兩部分,對這兩個部分進行歸並排序,排序後,再對兩個已經排序好的數組進行合並。這種思想可以用遞歸方式很容易實現。歸並排序的時間復雜度為O(nlogn),空間復雜度為O(n)。
實現代碼如下:
#include <stdio.h>
#include "common.h"
void merge(int data[], int p, int q, int r)
{
int i, j, k, n1, n2;
n1 = q - p + 1;
n2 = r - q;
int L[n1];
int R[n2];
for(i = 0, k = p; i < n1; i++, k++)
L[i] = data[k];
for(i = 0, k = q + 1; i < n2; i++, k++)
R[i] = data[k];
for(k = p, i = 0, j = 0; i < n1 && j < n2; k++)
{
if(L[i] > R[j])
{
data[k] = L[i];
i++;
}
else
{
data[k] = R[j];
j++;
}
}
if(i < n1)
{
for(j = i; j < n1; j++, k++)
data[k] = L[j];
}
if(j < n2)
{
for(i = j; i < n2; i++, k++)
data[k] = R[i];
}
}
void merge_sort(int data[], int p, int r)
{
if(p < r)
{
int q = (p + r) / 2;
merge_sort(data, p, q);
merge_sort(data, q + 1, r);
merge(data, p, q, r);
}
}
void test_merge_sort()
{
int data[] = {44, 12, 145, -123, -1, 0, 121};
printf("-------------------------------merge sort----------------------------\n");
out_int_array(data, 7);
merge_sort(data, 0, 6);
out_int_array(data, 7);
}
int main()
{
test_merge_sort();
return 0;
}
4.對於有n個結點的線性表(e0,e1,…,en-1),將結點中某些數據項的值按遞增或遞減的次序,重新排列線性表結點的過程,稱為排序。排序時參照的數據項稱為排序碼,通常選擇結點的鍵值作為排序碼。
若線性表中排序碼相等的結點經某種排序方法進行排序後,仍能保持它們在排序之前的相對次序,稱這種排序方法是穩定的;否則,稱這種排序方法是不穩定的。
在排序過程中,線性表的全部結點都在內存,並在內存中調整它們在線性表中的存儲順序,稱為內排序。在排序過程中,線性表只有部分結點被調入內存,並藉助內存調整結點在外存中的存放順序的排序方法成為外排序。
下面通過一個表格簡單介紹幾種常見的內排序方法,以及比較一下它們之間的性能特點。
排序方法
簡介
平均時間
最壞情況
輔助存儲
是否穩定
簡單排序
選擇排序
反復從還未排好序的那部分線性表中選出鍵值最小的結點,並按從線性表中選出的順序排列結點,重新組成線性表。直至未排序的那部分為空,則重新形成的線性表是一個有序的線性表。
O( )
O( )
O(1)
不穩定
直接插入排序
假設線性表的前面I個結點序列e0,e1,…,en-1是已排序的。對結點在這有序結點ei序列中找插入位置,並將ei插入,而使i+1個結點序列e0,e1,…,ei也變成排序的。依次對i=1,2,…,n-1分別執行這樣的插入步驟,最終實現線性表的排序。
O( )
O( )
O(1)
穩定
冒泡排序
對當前還未排好序的范圍內的全部結點,自上而下對相鄰的兩個結點依次進行比較和調整,讓鍵值大的結點往下沉,鍵值小的結點往上冒。即,每當兩相鄰比較後發現它們的排列順序與排序要求相反時,就將它們互換。
O( )
O( )
O(1)
穩定
希爾排序
對直接插入排序一種改進,又稱「縮小增量排序」。先將整個待排序列分割成為若乾子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時,再對全體記錄進行一次直接插入排序。
kn ln n
O( )
O(logn)
不穩定
快速排序
對冒泡排序的一種本質的改進。通過一趟掃視後,使待排序序列的長度能大幅度的減少。在一趟掃視後,使某個結點移到中間的正確位置,並使在它左邊序列的結點的鍵值都比它的小,而它右邊序列的結點的鍵值都不比它的小。稱這樣一次掃視為「劃分」。每次劃分使一個長序列變成兩個新的較小子序列,對這兩個小的子序列分別作同樣的劃分,直至新的子序列的長度為1使才不再劃分。當所有子序列長度都為1時,序列已是排好序的了。
O(nlogn)
O( )
O(logn)
不穩定
堆排序
一種樹形選擇排序,是對直接選擇排序的有效改進。一個堆是這樣一棵順序存儲的二叉樹,它的所有父結點(e[i])的鍵值均不小於它的左子結點(e[2*i+1])和右子結點(e[2*i+2])的鍵值。初始時,若把待排序序列的n個結點看作是一棵順序存儲的二叉樹,調整它們的存儲順序,使之成為一個堆,這時堆的根結點鍵值是最大者。然後將根結點與堆的最後一個結點交換,並對少了一個結點後的n-1結點重新作調整,使之再次成為堆。這樣,在根結點得到結點序列鍵值次最大值。依次類推,直到只有兩個結點的堆,並對它們作交換,最後得到有序的n個結點序列。
O(nlogn)
O(nlogn)
O(1)
不穩定
歸並排序
將兩個或兩個以上的有序子表合並成一個新的有序表。對於兩個有序子表合並一個有序表的兩路合並排序來說,初始時,把含n個結點的待排序序列看作有n個長度都為1的有序子表所組成,將它們依次兩兩合並得到長度為2的若干有序子表,再對它們作兩兩合並……直到得到長度為n的有序表,排序即告完成。
O(nlogn)
O(nlogn)
O(n)
穩定
後面根據各種排序演算法,給出了C語言的實現,大家在復習的時候可以做下參考。
u 選擇排序
void ss_sort(int e[], int n)
{ int i, j, k, t;
for(i=0; i< n-1; i++) {
for(k=i, j=i+1; j<n; j++)
if(e[k]>e[j]) k=j;
if(k!=i) {
t=e[i]; e[i]=e[k]; e[k]=t;
}
}
}
u 直接插入排序
void si_sort(int e[], int n)
{ int i, j, t;
for(i=0; i< n; i++) {
for(t=e[i], j=i-1; j>=0&&t<e[j]; j--)
e[j+1]=e[j];
e[j+1]=t;
}
}
u 冒泡排序
void sb_sort(int e[], int n)
{ int j, p, h, t;
for(h=n-1; h>0; h=p) {
for(p=j=0; j<h; j++)
if(e[j]>e[j+1]) {
t=e[j]; e[j]=e[j+1]; e[j+1]=t;
p=j;
}
}
}
u 希爾排序
void shell(int e[], int n)
{ int j, k, h, y;
for(h=n/2; h>0; h=h/2)
for(j=h; j<n; j++) {
y=e[j];
for(k=j-h; k>0&&y<e[k]; k-=h)
e[k+h]=e[k];
e[k+h]=y;
}
}
u 堆排序
void sift(e, n, s)
int e[];
int n;
int s;
{ int t, k, j;
t=e[s];
k=s; j=2*k+1;
while(j<n) {
if(j<n-1&&e[j]<e[j+1])
j++;
if(t<e[j]) {
e[k]=e[j];
k=j;
j=2*k+1;
}else break;
}
e[k]=t;
}
void heapsorp (int e[], int n)
{ int i, k, t;
for(i=n/2-1; i>=0; i--)
sift(e, n, i);
for(k=n-1; k>=1; k--) {
t=e[0]; e[0]=e[k]; e[k]=t;
sift(e, k, 0);
}
}
u 快速排序
void r_quick(int e[], int low, int high)
{ int i, j, t;
if(low<high) {
i=low; j=high; t=e[low];
while(i<j) {
while (i<j&&e[j]>t) j--;
if(i<j) e[I++]=e[j];
while (i<j&&e[i]<=t) i++;
if(I<j) e[j--]=e[i];
}
e[i]=t;
r_quick(e,low,i-1);
r_quick(w,i+1,high);
}
}
另外,外排序是對大型文件的排序,待排序的記錄存儲在外存中,在排序過程中,內存只存儲文件的一部分記錄,整個排序過程需進行多次的內外存間的交換。
*** 查找
查找就是在按某種數據結構形式存儲的數據集合中,找出滿足指定條件的結點。
按查找的條件分類,有按結點的關鍵碼查找、關鍵碼以外的其他數據項查找或其他數據項的組合查找等。按查找數據在內存或外存,分內存查找和外存查找。按查找目的,查找如果只是為了確定指定條件的結點存在與否,成為靜態查找;查找是為確定結點的插入位置或為了刪除找到的結點,稱為動態查找。
這里簡單介紹幾種常見的查找方法。
u 順序存儲線性表的查找
這是最常見的查找方式。結點集合按線性表組織,採用順序存儲方式,結點只含關鍵碼,並且是整數。如果線性表無序,則採用順序查找,即從線性表的一端開始逐一查找。而如果線性表有序,則可以使用順序查找、二分法查找或插值查找。
u 分塊查找
分塊查找的過程分兩步,先用二分法在索引表中查索引項,確定要查的結點在哪一塊。然後,再在相應塊內順序查找。
u 鏈接存儲線性表的查找
對於鏈接存儲線性表的查找只能從鏈表的首結點開始順序查找。同樣對於無序的鏈表和有序的鏈表查找方法不同。
u 散列表的查找
散列表又稱雜湊表,是一種非常實用的查找技術。它的原理是在結點的存儲位置和它的關鍵碼間建立一個確定的關系,從而讓查找碼直接利用這個關系確定結點的位置。其技術的關鍵在於解決兩個問題。
I. 找一個好的散列函數
❸ Rob Hess給出的sift代碼運行出現如下錯誤:error C2198: 「cvKMeans2」: 用於調用的參數太少,請大俠指教
這是源碼里針對找到圖像特徵點進行聚類的函數,運行到這里sift演算法已經結束了。可以試著吧調用kmeans演算法的部分注釋掉,只執行sift演算法然後打出來特徵點看一下效果。我也不明白在一張圖像上對特徵點聚類的意義何在。對多張圖像聚類還有意義。
❹ sift演算法的matlab程序有一段沒有看懂,請大神幫忙
這段matlab是個空殼,其核心是調用siftWin32.exe。(對windows)
Q1 這是pgm文件的格式要求。可以自己查去
Q2 !表示後面執行的命令是在系統shell里執行的。對windows來說就是命令提示符
Q3 那是可執行程序siftWin32.exe需要的參數
Q4 那是可執行程序siftWin32.exe需要的
❺ 各位大神,求一份尺度不變特徵變換(SIFT演算法)MATLAB實現的代碼,最好有注釋,小弟剛剛起步,謝謝了!
附件中是sift的matlab實現代碼,在matlab中直接點擊運行do_demo_3.m即可實現圖像匹配
do_demo_1.m可以顯示sift特徵點
具體的詳細用法你可以研究一下代碼
這份代碼是我目前在網上找到的最簡潔的代碼
希望對你能有所幫助