八大算法總結

 

文章目錄

  • 算法
    • 穩定性
    • 插入排序
      • 直接插入排序
      • 折半插入排序
      • 希爾排序
    • 交換排序
      • 冒泡排序
      • 快速排序
    • 選擇類排序
      • 簡單選擇排序
      • 堆排序
    • 歸併排序
    • 基數排序
    • 外部排序

 

算法

穩定性

選擇排序、快速排序、希爾排序、堆排序不是穩定的排序算法,java

冒泡排序、插入排序、歸併排序、基數排序是穩定的排序算法算法

插入排序

有一個已經 有序 的數據序列,要求在這個已經排好的數據序列中插入一個數,但要求插入後此數據序列仍然有序,這個時候就要用到一種新的排序方法——插入排序法,插入排序的基本操做就是將一個數據插入到已經排好序的有序數據中,從而獲得一個新的、個數加一的有序數據,算法適用於少許數據的排序,時間複雜度爲 O(n^2)。是穩定的排序方法。數組

  1. 從第一個元素開始,該元素能夠認爲已經被排序;
  2. 取出下一個元素,在已經排序的元素序列中從後向前掃描;
  3. 若是該元素(已排序)大於新元素,將該元素移到下一位置;
  4. 重複步驟 3,直到找到已排序的元素小於或者等於新元素的位置;
  5. 將新元素插入到該位置後;
  6. 重複步驟 2 ~ 5,直至最後一個元素。
import java.util.Arrays;

public class InsertSort {
    private static void insertSort(int[] arr) {
      int j; // 已排序列表下標
      int t; // 待排序元素
      for (int i = 1; i < arr.length; i++) {
        if (arr[i] < arr[i - 1]) {
          t = arr[i]; // 賦值給待排序元素
          for (j = i - 1; j >= 0 && arr[j] > t; j--) {
            arr[j + 1] = arr[j]; // 從後往前遍歷已排序列表,逐個和待排序元素比較,若是已排序元素較大,則將它後移
          }
          arr[j + 1] = t; // 將待排序元素插入到正確的位置
        }
      }
    }

    public static void main(String[] args) {
        int[] ints = {5, 3, 4, 1, 2};
        insertSort(ints);
        System.out.println(Arrays.toString(ints));
    }
}

直接插入排序

void InsertSort(ElemType A[],int n){
	int i,j;
	for(i=2;i<=n;i++)	
		if(A[i]<A[i-1]){	
			A[0]=A[i];	//複製爲哨兵,A[0]不存放元素
			for(j=i-1;A[0]<A[j];--j)
				A[j+1]=A[j];	//全部比待插入元素值大的都日後移一位,騰出空位
			A[j+1]=A[0];   		//複製到插入位置 
		}
}

折半插入排序

void InsertSort(ElemType A[],int n){
	int i,j,low,high,mid;
	for(i=2;i<=n;i++){	//i記錄的是待插入的元素下標,也就是說i-1以前的元素都是有序的	
		A[0]=A[i]; //保存待插入的值			
		low=1;high=i-1; 
		while(low<=high){	 //折半查找	
			mid=(low+high)/2;	
			if(A[mid].key>A[0].key) high=mid-1; 
			else low=mid+1;	
		}
         //找到了待插入的位置 接下來從後往前依次後移元素騰出位置
		for(j=i-1;j>=high+1;--j)A[j+1]=A[j];		
		A[high+1]=A[0];	//由於此時high指向的是待插入位置的前一位		
	}
}

希爾排序

void ShellSort (ElemType A[],int n){
               int i,j;
	for(dk=n/2;dk>=1;dk=dk/2)	    //初始增量爲總長度的一半,以後依次除2且向下取整,
                                                               //且最後一次要爲1
		for(i=dk+1;i<=n;++i)
			if(A[i].key<A[i-dk].key){  //A[i].key是待插入的關鍵字,i-dk以前的都是有序的,如          //果待插入的比有序序列最後一個小, 則須要進行排序(進入if語句塊),若是大則不須要(跳出if語句塊)
				A[0]=A[i];       //待插入關鍵字暫存在A[0]
				for(j=i-dk;j>0&&A[0].key<A[j].key; j-=dk)
                            //待插入關鍵字以前以dk爲增量的關鍵字只要比待插入關鍵字大的都日後移動dk位
					A[j+dk]=A[j];		
				A[j+dk]=A[0]; //找到了待插入的位置,就將待插入關鍵字插入這個位置			
			}
}

交換排序

冒泡排序

冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。 它重複地走訪過要排序的元素列, 依次比較兩個相鄰的元素 ,若是他們的順序(如從大到小、首字母從 A 到 Z)錯誤就把他們交換過來。走訪元素的工做是重複地進行直到沒有相鄰元素須要交換,也就是說該元素已經排序完成。 這個算法的名字由來是由於越大的元素會經由交換慢慢「浮」到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端同樣,故名「冒泡排序」。架構

  1. 比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。
  2. 對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。
  3. 針對全部的元素重複以上的步驟,除了最後一個。
  4. 持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。
import java.util.Arrays;

public class BubbleSort {
    public static void sort(int[] arr) {
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                //若是當前元素比後一位元素大 交換位置
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] ints = {5, 3, 4, 1, 2};
        sort(ints);
        System.out.println(Arrays.toString(ints));
    }
}

快速排序

快速排序(英語:Quicksort),又稱劃分交換排序(partition-exchange sort),簡稱快排,也是一種排序算法。最先由東尼·霍爾提出。在平均情況下,排序 n 個項目要 O(nlogn) 次比較。在最壞情況下則須要 O(n^2) 次比較,但這種情況並不常見。事實上,快速排序 O(nlogn) 一般明顯比其餘算法更快,由於它的內部循環(inner loop)能夠在大部分的架構上頗有效率地達成。ide

  1. 從數列中挑出一個元素,稱爲「基準」(pivot),
  2. 從新排序數列,全部比基準值小的元素擺放在基準前面,全部比基準值大的元素擺在基準後面(相同的數能夠到任何一邊)。在這個分割結束以後,該基準就處於數列的中間位置。這個稱爲分割(partition)操做。
  3. 遞歸地(recursively)把小於基準值元素的子數列和大於基準值元素的子數列排序。
  4. 遞歸到最底部時,數列的大小是零或一,也就是已經排序好了。這個算法必定會結束,由於在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
int Partition(ElemType A[],int low,int high){  //low是當前待排序的序列起始下標,high是末尾下標
	ElemType pivot=A[low];	//第一個元素做爲樞軸
	while(low<high){		
		while(low<high&&A[high]>=pivot) --high;//先從末尾往前找到第一個比樞軸小的元素
		A[low]=A[high]; 	//用high的元素替換low的元素
		while(low<high&&A[low]<=pivot) ++low; //再從開頭日後找到第一個比樞軸大的元素
		A[high]=A[low]; 	//用low的元素替換high的元素
	}
	A[low]=pivot;			//樞軸元素存放到最終位置
	return  low; 			//返回存放樞軸的最終位置
}

void QuickSort(ElemType A[],int low,int high){
	if(low<high){   //low和high值要合法			
		int pivotpos=Partition(A,low,high);	
		QuickSort(A,low,pivotpos-1); //分治遞歸左半部分	
		QuickSort(A,pivotpos+1,high); //分治遞歸右半部分
	}
}

import java.util.Arrays;

public class QuickSort {
    public static void sort(int[] arr, int head, int tail) {
        if (head >= tail || arr == null || arr.length <= 1) {
            return;
        }
        //設置數組的起始位置 i 結束位置j 基準 pivot 爲數組的中間
        int i = head, j = tail, pivot = arr[(head + tail) / 2];
        while (i <= j) {
            //當數組小於基準 循環結束後 至關於i所處的位置的值爲大於基準的元素
            while (arr[i] < pivot) {
                ++i;
            }
            //當數組大於基準 循環結束後 至關於j所處的位置的值爲小於於基準的元素
            while (arr[j] > pivot) {
                --j;
            }
            //若是i<j 那麼則將交互i j對應位置的值
            if (i < j) {
                int t = arr[i];
                arr[i] = arr[j];
                arr[j] = t;
                //將指針繼續移動
                ++i;
                --j;
            } else if (i == j) {
//若是i=j 那麼說明本次排序已經結束 將i++ 若是這裏不使用i++ 那麼後面的sort(arr,i,tail)將改成arr(arr,i+1,tail)
                ++i;
            }
        }
        //繼續將數組分割
        sort(arr, head, j);
        sort(arr, i, tail);
    }

    public static void main(String[] args) {
        int[] ints = {5, 3, 4, 1, 2};
        sort(ints, 0, ints.length - 1);
        System.out.println(Arrays.toString(ints));
    }
}

選擇類排序

簡單選擇排序

void SelectSort(ElemType A[],int n){
	for(i=0;i<n-1;i++){	  //依次從後面序列中選擇當前最小的元素做爲第i個元素 最後一個元素不須要排序
	       min=i;	                   //min存的是當前最小元素所在下標,初值設爲第i個
	       for(j=i+1;j<n;j++)             //從第i個元素日後找,一直要找到最後一個元素
	            if(A[j]<A[min]) min=j;	   //若是這個值更小,則更新min值爲這個更小的元素所在下標
	       if(min!=i) {                        //若是第i個元素不是剩下元素最小的,則和最小的進行交換
                           ElemType temp=A[i];
                           A[i]=A[min];
                           A[min]=temp;
                    } 	
	}
}

堆排序

void BuildMaxHeap(ElemType A[],int len){
	for(int i=len/2;i>0;i--) AdjustDown(A,i,len); //由數組下標高處往低處 從第一個可能須要調整的非葉結點
                                                                             // 開始檢查,直到根結點(注意根結點下標不是0,是從1開始存儲)
}
void AdjustDown(ElemType A[],int k,int len){ //A是存儲堆的數組,k是須要檢查的結點下標,len是堆中結點個數
	A[0]=A[k]; 		           //A[0]暫存這個須要檢查的結點值
	for(i=2*k;i<=len;i*=2){		//從這個結點的左孩子開始往下比較,
                                                                          // 若是發生交換,對交換過的結點繼續和它的孩子比較
		if(i<len&&A[i]<A[i+1])i++;	//若是右孩子大一些,就只要考慮和右孩子比較
		if(A[0]>=A[i])  break;	//若是這個結點的值不小於它的較大孩子結點值 則不須要交換
		else{ 
			A[k]=A[i];	//若是這個結點的值小於它的較大孩子
                                                                          //結點值則將較大的孩子結點值賦值給該結點	
			k=i;		//i賦值給k也就是從i開始繼續往下檢查 直到全部結點檢查結束	
		}
	}
	A[k]=A[0];	//檢查到最後k的值就是最後一輪交換過的結點位置下標 將該結點換過去		
}

歸併排序

歸併排序(MERGE-SORT)是創建在歸併操做上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。oop

  1. 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列ui

  2. 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置3d

  3. 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置指針

  4. 重複步驟 3 直到某一指針到達序列尾code

  5. 將另外一序列剩下的全部元素直接複製到合併序列尾

import java.util.Arrays;

public class MergeSort {

    public static void mergeSort(int[] arrays, int left, int right) {
                // 若是數組還能夠拆分
        if (left < right) {
            //數組的中間位置
            int middle = (left + right) / 2;
            //拆分左邊數組
            mergeSort(arrays, left, middle);
            //拆分右邊數組
            mergeSort(arrays, middle + 1, right);
            //合併
            merge(arrays, left, middle, right);
        }
    }


    /**
     * 合併數組
     */
    public static void merge(int[] arr, int left, int middle, int right) {
        //申請合併空間 大小爲兩個已經排序序列之和
        int[] temp = new int[right - left + 1];
        //i 和 j爲兩個已經排好序的數組的起始位置
        int i = left;
        int j = middle + 1;
        int k = 0;
        //排序
        while (i <= middle && j <= right) {
            //將比較小的數組放入合併空間
            if (arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }
        //將左邊剩餘元素寫入合併空間
        while (i <= middle) {
            temp[k++] = arr[i++];
        }
        //將右邊剩餘的元素寫入合併空間
        while (j <= right) {
            temp[k++] = arr[j++];
        }
        //將排序後的數組寫回原來的數組
        for (int l = 0; l < temp.length; l++) {
            arr[l + left] = temp[l];
        }

    }

    public static void main(String[] args) {
        int[] ints = {5, 3, 4, 1, 2};
        mergeSort(ints,0,ints.length-1);
        System.out.println(Arrays.toString(ints));
    }
}

基數排序

ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //輔助數組B(動態分配內存)

void Merge(ElemType A[],int low,int mid,int high){
//表A的兩段A[low…mid]和A[mid+1…high]各自有序,將它們合併成一個有序表
	for(int k=low;k<=high;k++)B[k]=A[k];		//將A中全部元素複製到B中
	for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){  k是歸併以後數組的下標計數器
		if(B[i]<=B[j])   			//比較B的左右兩段中的元素
			A[k]=B[i++];			//將較小值複製到A中
		else
			A[k]=B[j++];
	}
	while(i<=mid)	A[k++]=B[i++];	//若第一個表未檢測完,直接將剩下的部分複製過來
	while(j<=high)	A[k++]=B[j++];	//若第二個表未檢測完,直接將剩下的部分複製過來
}

外部排序

watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索