1. 程式人生 > >資料結構和演算法精講版(陣列、棧、佇列、連結串列、遞迴、排序、二叉樹、紅黑樹、堆、雜湊表)Java版

資料結構和演算法精講版(陣列、棧、佇列、連結串列、遞迴、排序、二叉樹、紅黑樹、堆、雜湊表)Java版

查詢和排序是最基礎也是最重要的兩類演算法,熟練地掌握這兩類演算法,並能對這些演算法的效能進行分析很重要,這兩類演算法中主要包括二分查詢、快速排序、歸併排序等等。我們先來了解查詢演算法!
順序查詢:
順序查詢又稱線性查詢。它的過程為:從查詢表的最後一個元素開始逐個與給定關鍵字比較,若某個記錄的關鍵字和給定值比較相等,則查詢成功,否則,若直至第一個記錄,其關鍵字和給定值比較都不等,則表明表中沒有所查記錄查詢不成功,它的缺點是效率低下。
二分查詢:
二分查詢又稱折半查詢,對於有序表來說,它的優點是比較次數少,查詢速度快,平均效能好。
二分查詢的基本思想是將n個元素分成大致相等的兩部分,取a[n/2]與目標值x做比較,如果x=a[n/2],則找到x,演算法中止,如果x小於a[n/2],則只要在陣列a的左半部分繼續搜尋x,如果x>a[n/2],則只要在陣列a的右半部搜尋x.程式碼實現如下:

public int funBinSearch(int[] array,int data){

int low=0;
int high=array.length-1;

while(low<=high){
int mid=(low+high)/2;
if(data==array[mid]){
return mid;
}else if(data<array[mid]){
high=mid-1;
}else{
low=mid+1;
}
}
return -1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
排序是計算機程式設計中的一種重要操作,它的功能是將一個數據元素(或記錄)的任意序列,重新排列成一個按關鍵字有序的序列。下面主要對一些常見的排序演算法做介紹.先來了解氣泡排序!
氣泡排序:
氣泡排序的基本思想是:設排序序列的記錄個數為n,進行n-1次遍歷,每次遍歷從開始位置依次往後比較前後相鄰元素,這樣較大的元素往後移,n-1次遍歷結束後,序列有序。
需要注意的是,如果在某次遍歷中沒有發生交換,那麼就不必進行下次遍歷,因為序列已經有序。程式碼實現如下:

public void bubbleSort(int[] array){
boolean flag=true;
for(int i=0;i<array.length-1&&flag;i++){
//如果在某次遍歷中沒有發生交換,那麼就不必再進行下次遍歷,因為序列已經有序
flag=false;
for(int j=0;j<array.length-1-i;j++){
if(array[j]>array[j+1]){
int temp=array[i];
array[j]=array[j+1];
array[j+1]=temp;
flag=true;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
簡單選擇排序:
簡單選擇排序的思想是:設排序序列的記錄個數為n,每一輪進行n-2-i次選擇,每次在n-i-1(i = 1,2,…,n-1)個記錄中選擇關鍵字最小的記錄作為有效序列中的第i個記錄。程式碼實現如下:

public void selectionSort(int[] array){
for(int i=0;i<array.length-1;i++){
int mink=i;
//每次從未排序陣列中找到最小值的座標
for(int j=i+1;j<array.length;j++){
if(array[j]<array[mink]){
mink=j;
}
}

//將最小值放在最前面
if(mink!=i){
int temp=array[mink];
array[mink]=array[i];
array[i]=temp;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
直接插入排序:
直接插入的思想是:是將一個記錄插入到已排好序的有序表中,從而得到一個新的、記錄數增1的有序表。

public void insertSort(int[] array){
int j;
for(int i=1;i<array.length;i++){
int temp=array[i];
j=i-1;
while(j>-1&&temp<array[j]){
array[j+1]=array[j];
j--;
}
array[j+1]=temp;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
希爾排序:

希爾排序又稱“縮小增量排序”,它是基於直接插入排序的以下兩點性質而提出的一種改進:(1) 直接插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率。(2) 直接插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。快速簡單理解——希爾排序.

public void xier(int[] arrays,int n){
int gap=n/2;
for(;gap>0;gap=gap/2){
for(int i=0;i<n;i++){
int temp=a[i];
int j=i-gap;
while(j>=0&&temp<a[j]){
a[j+gap]=a[j];
j=j-gap;
}
a[j+gap]=temp;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
快速排序:
快速排序的主要思想是:在待排序的序列中選擇一個稱為主元的元素,將陣列分為兩部分,使得第一部分中的所有元素都小於或等於主元,而第二部分中的所有元素都大於主元,然後對兩部分遞迴地應用快速排序演算法。簡單理解 快速排序演算法.

public void quickSort(int[] s,int left,int right){
if(1<right){
int i=left,j=right,temp=s[left];
while(i<j){
while(i<j&&s[j]>=temp){//從右向左找第一個小於temp的數
j--;
}
if(i<j){
s[i++]=s[j];
}
while(i<j&&s[i]<temp){//從左向右找第一個大於等於temp的數
i++;
}
if(i<j){
s[j--]=s[i];
}
}
s[i]=temp;
quickSort(s,left,i-1);//遞迴呼叫(分治法)
quickSort(s,i+1,right);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
堆排序:
在介紹堆排序之前首先需要了解堆的定義,n個關鍵字序列K1,K2,…,Kn稱為堆,當且僅當該序列滿足如下性質(簡稱為堆性質):(1) ki <= k(2i)且 ki <= k(2i+1) (1 ≤ i≤ n/2),當然,這是小根堆,大根堆則換成>=號。
如果將上面滿足堆性質的序列看成是一個完全二叉樹,則堆的含義表明,完全二叉樹中所有的非終端節點的值均不大於(或不小於)其左右孩子節點的值。
堆排序的主要思想是:給定一個待排序序列,首先經過一次調整,將序列構建成一個大頂堆,此時第一個元素是最大的元素,將其和序列的最後一個元素交換,然後對前n-1個元素調整為大頂堆,再將其第一個元素和末尾元素交換,這樣最後即可得到有序序列。堆排序就這麼簡單.

//建堆
//引數:看作是完全二叉樹,當前父節點位置,節點總數
public void heapify(int[] arrays,int currentRootNode,int size){

if(currentRootNode<size){
//左節點和右節點的位置
int left=2*currentRootNode+1;
int right=2*currentRootNode+2;

//把當前父節點看成是最大的
int max=currentRootNode;
if(left<size){
//如果比當前根元素要大,記錄它的位置
if(arrays[max]<arrays[left]){
max=left;
}
}
if(right<size){
//如果比當前根元素要大,記錄它的位置
if(arrays[max]<arrays[right]){
max=right;
}
}
//如果最大的不是根元素位置,那麼就交換
if(max!=currentRootNode){
int temp=arrays[max];
arrays[max]=arrays[currentRootNode];
arrays[currentRootNode]=temp;

//繼續比較,知道完成一次堆建
heapify(arrays,max,arrays.length);
}
}
}

//完成一次建堆,最大值在堆的頂部(根節點)
public void maxHeapify(int[] arrays,int size){

//從陣列的尾部開始,直到第一個元素(角標為0)
for(int i=size-1;i>=0;i--){
heapify(arrays,i,size);
}
}

for(int i=0;i<arrays.length;i++){

//每次建堆就可以排除一個元素
maxHeapify(arrays,arrays.length-i);

//交換
int temp=arrays[0];
arrays[0]=arrays[arrays.length-1-i];
arrays[length-1-i]=temp;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
歸併排序:
歸併排序 (merge sort) 是一類與插入排序、交換排序、選擇排序不同的另一種排序方法。歸併的含義是將兩個或兩個以上的有序表合併成一個新的有序表。它是一種穩定的排序,java.util.Arrays類中的sort方法就是使用歸併排序的變體來實現的。“深入理解”—歸併排序演算法.

原文:https://blog.csdn.net/lulalei/article/details/79712579
版權宣告:本文為博主原創文章,轉載請附上博文連結!