資料結構的常見內部排序

2021-09-28 15:46:22 字數 4570 閱讀 5334

排序是計算機內經常進行的一種操作,其目的是將一組「無序」的記錄序列調整為「有序」的記錄序列。分內部排序和外部排序,若整個排序過程不需要訪問外存便能完成,則稱此類排序問題為內部排序。反之,若參加排序的記錄數量很大,整個序列的排序過程不可能在記憶體中完成,則稱此類排序問題為外部排序。內部排序的過程是乙個逐步擴大記錄的有序序列長度的過程。

本文將介紹幾種常見的內部排序

以下排序方法通常是建立在順序表上,也就是我們通常所說的陣列

時間複雜度o(n2)

演算法思想:

l(0)不存放元素,作為「哨兵」(起監督作用),如下圖所示,乙個完整       元素陣列邏輯上可看做成下面四個板塊,哨兵、有序序列、l(i)、無序序列

目的是將元素l(i)插入前面板塊的有序序列中,l(1)只有乙個元素,故預設有序,然後將第二個元素,也就是l(2)插入到前面的有序板塊中,首先將自己賦值給l(0),然後利用哨兵l(0)與前面有序板塊的末位向前依次比較大小,如遇到比自己大的元素,則將該大元素向後挪一位,一直向前比較,直到遇到比自己小(演算法不穩定)/小於等於(演算法穩定)的元素(最差情況是遇到與自己相等的哨兵),然後插入這個元素的前面一位(直接將哨兵的值賦值給其前面一位)

舉例說明:4、6、8、5、3(哨兵l(0)= l(i)= 5)

(4、6、8 處於有序序列板塊,現要將5插入有序板塊中;)

1.哨兵l(0)=5 與8比較,5小於8,8向後挪位,整個序列變為 4、6、8、8、3;

2.下一步:6與l(0)比較,6比l(0)大,6向後挪位,序列變為4、6、6、8、3;

3.下一步:4與l(0)比較,4比l(0)小,不挪位,將哨兵插入,第乙個6換成l(0),序列變為4、5、6、8、3;

4.後面的 3 進行插入排序同理

具體程式實現如下:

//插入排序

void

insertion_sort

(int a,

int n)

a[j+1]

=a[0];

//直接將哨兵的值賦值給其前面一位}}

}

時間複雜度o(n2)

演算法思想:主體思想與上文中的直接插入排序相同,區別在於簡單插入排序是在有序區逐一與哨兵比較,而折半插入排序是先定位到待插入位置loci,然後將有序區loci後面的元素向後挪位,最後將哨兵賦值安置在待插入位置loci;

注意這裡就是為了找到失敗位置,即使有序區有與哨兵相同的元素,也不能像之前我們學習的折半查詢一樣退出(break),而是在high//折半插入排序

void

half_insert_sort

(int a,

int n)

else

}for

(j = i-

1; j>high;

--j)

a[high+1]

=a[0];

//將哨兵賦值安置在待插入位置loci

}}空間複雜度為o(1)、時間複雜度約為o(n1.3)、最壞情況下時間複雜度為o(n2)

演算法思想:隸屬於插入排序,將整個排序列表以dk增量序列(此增量序列為認為隨機定義,唯一要求是增量序列的最後乙個元素是1,如5、3、1或者6、5、3、1或者9、5、3、1都可以)分成dk個組,然後在各個組中分別進行插入排序,注意是插入排序(簡單插入排序),不是比較然後交換位置

常用增量序列(希爾推薦)是dk = n/2、dk=dk/2、、、1

具體程式實現如下:

(注意最內部的for迴圈中j>0是必須的,這個是很重要的for迴圈終止條件)

//希爾排序

void

shell_sort

(int a,

int n)

a[j+dk]

=a[0];

}}}}

時間複雜度o(n2)

演算法思想:氣泡排序比較簡單,也見得比較多,也就是在原n個兩兩比較,然後一直將大的元素往後排(兩兩交換位置),直到最後,實現最大(最小)元素浮出,也就是冒泡過程,接下來在剩下的n-1個元素中同樣進行此操作。

具體程式實現如下:

//氣泡排序

void

bubble_sort

(int a,

int n)}if

(flag ==

false)}

}

下文講解快速排序應該是很清晰了,可檢視下文,用python解釋的,不會python的也能看明白

利用python詳講快速排序演算法

時間複雜度o(n2)

簡單選擇是穩定的(參考於嚴蔚敏老師主編的《資料結構》)

演算法思想:每次找到剩餘元素的最小元素,然後將每趟最前面元素與該最小元素互換位置,實現最小元素沉底,最小元素一次存放於i=1、2、3…的位置

外層迴圈實現驅動,定位於每趟的最前面元素;內層迴圈致力於尋找每趟剩餘元素中的最小元素的座標;然後回到外層迴圈,將每趟最前面元素與該最小元素互換位置。

具體程式實現如下:

//選擇排序

void

select_sort

(int a,

int n)

} tempelement = a[i]

; a[i]

= a[tempkey]

; a[tempkey]

= tempelement;

}}

演算法思想:與鍊錶的歸併排序一樣的原理。

區別:在於順序錶用的是遞迴的方法,鍊錶中用的是迴圈。

相同:宣告備用空陣列(鍊錶中的是空鍊錶),然後每次歸併比較,將大的數放入備用陣列,最後將備用陣列中的值複製進入源陣列,遞迴實現的時候,能實現分塊存入不同的地方。

int a=

;//a[0]是哨兵,不存放元素

display

(a,12);

int b[12]

=;merge_sort

(a,1,11

,b);

//歸併排序

display

(a,12

);

//歸併排序

void

merge_sort

(int a,

int low,

int high,

int b)

return;}

void

merge

(int a,

int low,

int mid,

int high,

int b)

else

}//如果兩段小序列中的任何一串行未排完

while

(begin_first<=mid)

while

(begin_second<=high)

//printf("b: ");①

//display(b,i);②

//將備份陣列b排序元素還原到a陣列

for(i = low; i <= high;

++i)

}

每次備份陣列中的元素複製進入源陣列時,存入的下標為(我這裡下標0不存放元素):

1、21、2、3

1、2、3(4、5)

1、2、3、4、5

…舉例:如果我開啟上面**中的①②的注釋,結果如下:

演算法思想:逐層剝離(個位、十位、百位…),然後根據每次剝離的數放到不同的佇列中(此處用的是乙個10維陣列,此處命名為桶),然後按佇列(先進先出,因此穩定)讀出,這串串行中最高位有多少位,就迴圈多少次,就可以逐個分離排序

//基數排序

void

radix_sort

(int a,

int n)

//barrel桶歸零

for(

int i =

0; i <10;

++i)

}//將每個元素分裝各個桶

for(

int i =

1; i < n;

++i)

//將元素從各個桶中取出來放到a陣列中

base =1;

for(

int j =

0; j <10;

++j)}}

}}intgetdigits

(int a,

int n)

while

(tempvalue/

10!=0)

if(maxdigits < count)

}return maxdigits;

}

最後,給出各個排序的效能比較,希望能有所收穫~

資料結構 內部排序

內部排序演算法 時間複雜度 o n 2 o n 2 o n 2 空間複雜度 o 1 o 1 o 1 演算法名稱 插入 選擇 冒泡 演算法名稱 希爾 堆 快速 歸併 基數 空間複雜度 o 1 o 1 o logn o n o 2rd 時間複雜度 o nlogn o nlogn o nlogn o nl...

資料結構6 2內部排序

假設含n個記錄的序列為 其對應的關鍵字序列為 這些關鍵字的排列方式有多種,其中至少有一種排列方式能使得關鍵字之間存在著這樣乙個關係 kp1 kp2 kpn 按此關係將記錄序列重新排列為 即為有序記錄,將這一過程稱為排序。若在乙個記錄序列中ki kj,且在排序前的序列中ri領先於rj。若在排序後的序列...

資料結構 內部排序法

總結一些演算法的實現 交換排序 1.冒泡演算法 typedef struct arr1 arr1 void bubblesort arr1 goal,int n if flag m沒有交換時證明排玩了,跳出迴圈結束排序。return 2.快速排序 時間複雜度為o nlog2n 空間複雜度為o log...