日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

九大排序算法Java实现

發布時間:2023/12/18 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 九大排序算法Java实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前學習數據結構與算法時花了三天時間整理九大排序算法,并采用Java語言來實現,今天第一次寫博客,剛好可以把這些東西從總結的文檔中拿出來與大家分享一下,同時作為自己以后的備忘錄。 ??

1.排序算法時間復雜度、穩定性分類:

2.排序算法問題描述與實現

2.1冒泡排序(交換排序-穩定)

【問題描述】對于一個int數組,請編寫一個冒泡排序算法,對數組元素排序。?
問題分析:冒泡排序,顧名思義,從前往后遍歷,每次遍歷在末尾固定一個最大值。

易錯點:每次內層循環結束都會在末尾確定一個元素的位置,因此內層循環的判斷條件要減去外層的循環次數i

public int[] BobbleSort(int[] array){?

???????? for(int i=0;i<array.length-1;i++){ ?

??????????? for(int j=0;j<array.length-1-i;j++){ ?//內層循環,注意array.length-1-i,一定要-i

??????????????? swap(array,j,j+1);//交換數據元素的方法

???????? ?? }

???????? }

???????? return array;

????? }

????? public void swap(int[] array,int i,int j){//交換數據元素的方法

???????? if(array[i]>array[j]){

??????????? int temp=array[i];

??????????? ?array[i]=array[j];

??????????? ?array[j]=temp;

???????? }

????? }

冒泡排序的改進:加一個布爾型的flag,當某一趟冒泡排序沒有元素交換時,則冒泡結束,元素已經有序,可以有效的減少冒泡次數。

?

2.2 選擇排序(不穩定)

【問題描述】對于一個int數組,請編寫一個選擇排序算法,對數組元素排序。??
問題分析:選擇排序,從前往后遍歷,每次遍歷從頭開始依次選擇最小的來排序。

注意點:

【初始升序】:交換0次,時間復雜度為o(n); 【初始降序】:交換n-1次,時間復雜度為o(n^2)。

【特點】:交換移動數據次數少,比較次數多。

?? public int[] choose(int[] array){

????? for(int i=0;i<array.length-1;i++){

???????? int min=i;

???????? for (int j = i+1; j < array.length; j++) {

??????????? if(array[min]>array[j])

??????????????? min=j;

???????? }

???????? if(i!=min){

??????????? swap(array,i,min);

???????? }

????? }

????? return array;

?? }

??public?void?swap(int[] array,int?i,int?j){

??????if(array[i]>array[j]){

?????????int?temp=array[i];

???????? ?array[i]=array[j];

???????? ?array[j]=temp;

????? }

?? }

?

2.3 直接插入排序(穩定的 )

【問題描述】對于一個int數組,請編寫一個插入排序算法,對數組元素排序。??
問題分析:插入排序,從前往后遍歷,每次遍歷確定一個元素的位置,下一個元素從后往前依次與排序好的元素比較,類似于摸撲克牌。

注意點:假定n是數組的長度,首先假設第一個元素被放置在正確的位置上,這樣僅需從1-n-1范圍內對剩余元素進行排序。對于每次遍歷,從0-i-1范圍內21.的元素已經被排好序,每次遍歷的任務是:通過掃描前面已排序的子列表,將位置i處的元素定位到從0到i的子列表之內的正確的位置上。將arr[i]復制為一個名為target的臨時元素。向下掃描列表,比較這個目標值target與arr[i-1]、arr[i-2]的大小,依次類推。這個比較過程在小于或等于目標值的第一個元素(arr[j])處停止,或者在列表開始處停止(j=0)。在arr[i]小于前面任何已排序元素時,后一個條件(j=0)為真,因此,這個元素會占用新排序子列表的第一個位置。在掃描期間,大于目標值target的每個元素都會向右滑動一個位置(arr[j]=arr[j-1])。一旦確定了正確位置j,目標值target(即原始的arr[i])就會被復制到這個位置。與選擇排序不同的是,插入排序將數據向右滑動,并且不會執行交換。

?? public int[] insert1(int[] array){

????? for(int i=1;i<array.length;i++){

???????? int j=i;

???????? int temp=array[i];

???????? while(j>0&&array[j-1]>temp){

??????????? array[j]=array[j-1];//元素右移

??????????? j--;

???????? }

???????? array[j]=temp;

????? }

????? return array;

?? }

?

2.4?希爾排序(2for循環+最后一個while,不穩定

問題描述:對于一個int數組,請編寫一個希爾排序算法,對數組元素排序。??
問題分析:希爾排序是改進的插入排序,算法先將要排序的一組數按某個增量d(n/2,n為要排序數的個數)分成若干組,每組中記錄的下標相差d.對每組中全部元素進行直接插入排序,然后再用一個較小的增量(d/2)對它進行分組,在每組中再進行直接插入排序。當增量減到1時,進行直接插入排序后,排序完成。希爾排序法(縮小增量法) 屬于插入類排序,是將整個無序列分割成若干小的子序列分別進行插入排序的方法。

  • public int[] hillInsert(int[] array){
  • ??? for (int d = array.length>>1; d>=1; d=d>>1) {
  • ?????? for(int i=d;i<array.length;i++){
  • ????????? int j=i;
  • ????????? int temp=array[i];
  • ????????? while(j>=d&&array[j-d]>temp){
  • ???????????? array[j]=array[j-d];
  • ???????????? j-=d;
  • ????????? }
  • ????????? array[j]=temp;
  • ?????? }
  • ??? }
  • ??? return array;
  • }

2.5.堆排序(不穩定)

?問題描述:對于一個int數組,請編寫一個堆排序算法,對數組元素排序。??
問題分析:
堆數據結構是一種數組對象,它可以被視為一科完全二叉樹結構(完全二叉樹是由滿二叉樹而引出來的。對于深度為K的,有n個結點的二叉樹,當且僅當其每一個結點都與深度為K的滿二叉樹中編號從1至n的結點一一對應時稱之為完全二叉樹)。它的特點是父節點的值大于(小于)兩個子節點的值(分別稱為大頂堆和小頂堆)。它常用于管理算法執行過程中的信息,應用場景包括堆排序優先隊列等。

完全二叉樹性質:如果i>1,則雙親是結點[i/2]。也就是說下標i與2i和2i+1是雙親子女關系。?當排序對象為數組時,下標從0開始,所以下標 i 與下標 2i+1和2i+2是雙親子女關系。

算法思路:

  • 堆排序:(大根堆)
  • ①將存放在array[0,...,n-1]中的n個元素建成初始堆;
  • ②將堆頂元素與堆底元素進行交換,則序列的最大值即已放到正確的位置;
  • ③但此時堆被破壞,將堆頂元素向下調整使其繼續保持大根堆的性質,再重復第②③步,直到堆中僅剩下一個元素為止。
  • 堆排序算法的性能分析:
  • 空間復雜度:o(1);
  • 時間復雜度:建堆:o(n),每次調整o(log n),故最好、最壞、平均情況下:o(n*logn);
  • 穩定性:不穩定
  • public static int[] heapMax(int[] array){ ?//建立大根堆
  • ??? for(int i=(array.length-2)/2;i>=0;i--){
  • ?????? buildHeap(array,i,array.length);
  • ??? }
  • ??? return array;
  • }
  • private static void buildHeap(int[] array, int k, int length) { ?//建堆方法
  • ??? // TODO Auto-generated method stub
  • ??? int temp=array[k];
  • ??? for(int i=2*k+1;i<length-1;i=2*i+1){
  • ?????? if(array[i]<array[i+1]){
  • ????????? i++;
  • ?????? }
  • ?????? if(temp>=array[i])
  • ????????? break;
  • ?????? else{
  • ????????? array[k]=array[i];
  • ????????? k=i;
  • ?????? }
  • ??? }?
  • ?????? array[k]=temp;
  • }
  • public static int[] heapSortArray(int[] array){ //進行堆排序
  • ??? ?array=heapMax(array);??
  • ??? for (int i =array.length-1; i >0; i--) {
  • ?????? int temp=array[0];???
  • ?????? array[0]=array[i];
  • ?????? array[i]=temp;
  • ?????? buildHeap(array,0,i);
  • ??? }
  • ??? return array;
  • }

?

2.6 歸并排序(穩定)

問題描述:對于一個int數組,請編寫一個歸并排序算法,對數組元素排序。?
問題分析:歸并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。首先考慮下如何將將二個有序數列合并。這個非常簡單,只要從比較二個數列的第一個數,誰小就先取誰,取了后就在對應數列中刪除這個數。然后再進行比較,如果有數列為空,那直接將另一個數列的數據依次取出即可。可以看出合并有序數列的效率是比較高的,可以達到O(n)。

解決了上面的合并有序數列問題,再來看歸并排序,其的基本思路就是將數組分成二組A,B,如果這二組組內的數據都是有序的,那么就可以很方便的將這二組數據進行排序。如何讓這二組組內數據有序了?

可以將A,B組各自再分成二組。依次類推,當分出來的小組只有一個數據時,可以認為這個小組組內已經達到了有序,然后再合并相鄰的二個小組就可以了。這樣通過先遞歸的分解數列,再合并數列就完成了歸并排序。

?? public int[] mergeSort(int[] A, int n) {

?? ?????? //歸并排序,遞歸做法,分而治之

?? ??????? mSort(A,0,n-1);

?? ??????? return A;

?? ??? }

?

?? ??? private void mSort(int[] A,int left,int right){

??? //分而治之,遞歸常用的思想,跳出遞歸的條件

??? if(left>=right){

??????? return;

??? }

??? //中點

??? int mid = (left+right)/2;

??? //有點類似后序遍歷!

??? mSort(A,left,mid);

??? mSort(A,mid+1,right);

??? merge(A,left,mid,right);

}

//將左右倆組的按序子序列排列成按序序列

private void merge(int[] A,int left,int mid,int rightEnd){

??? //充當tem數組的下標

??? int record = left;

??? //最后復制數組時使用

??? int record2 = left;

??? //右子序列的開始下標

??? int m =mid+1;

??? int[] tem = new int[A.length];

??? //只要left>mid或是m>rightEnd,就跳出循環

??? while(left<=mid&&m<=rightEnd){

??????? if(A[left]<=A[m]){

??????????? tem[record++]=A[left++];

??????? }else{

??????????? tem[record++]=A[m++];

??????? }

??? }

??? while(left<=mid){

??????? tem[record++]=A[left++];

??? }

??? while(m<=rightEnd){

??????? tem[record++]=A[m++];

??? }

??? //復制數組

??? for( ;record2<=rightEnd;record2++){

??????? A[record2] = tem[record2];

??? }

}

?

2.7 快速排序算法(不穩定)

問題描述:對于一個int數組,請編寫一個快速排序算法,對數組元素排序。?
問題分析:快速排序(Quicksort)是對冒泡排序的一種改進,使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)。

從數列中挑出一個元素,稱為”樞軸”(pivot)。重新排序數列,所有元素比樞軸值小的擺放在基準前面,所有元素比樞軸值大的擺在樞軸的后面(相同的數可以到任一邊)。

在這個分區結束之后,該樞軸就處于數列的中間位置。這個稱為分區(partition)操作。遞歸地(recursive)把小于樞軸值元素的子數列和大于樞軸值元素的子數列排序。

  • public static final void quickSort(int[] array, intstart, intend) {
  • ???? ??// i相當于助手1的位置,j相當于助手2的位置
  • ???? ??int i = start, j = end;
  • ???? ??int pivot = array[i]; // 取第1個元素為基準元素
  • ???? ??int emptyIndex = i; // 表示空位的位置索引,默認為被取出的基準元素的位置
  • ???? ??// 如果需要排序的元素個數不止1個,就進入快速排序(只要i和j不同,就表明至少有2個數組元素需要排序)
  • ???? ??while (i < j) {
  • ???? ????// 助手2開始從右向左一個個地查找小于基準元素的元素
  • ???? ????while (i < j && pivot <= array[j])
  • ???? ??????j--;
  • ???? ????if (i < j) {
  • ???? ??????// 如果助手2在遇到助手1之前就找到了對應的元素,就將該元素給助手1的"空位",j成了空位
  • ???? ??????array[emptyIndex] = array[emptyIndex = j];
  • ???? ????}
  • ???? ?????
  • ???? ????// 助手1開始從左向右一個個地查找大于基準元素的元素
  • ???? ????while (i < j && array[i] <= pivot)
  • ???? ??????i++;
  • ???? ????if (i < j) {
  • ???? ??????// 如果助手1在遇到助手2之前就找到了對應的元素,就將該元素給助手2的"空位",i成了空位
  • ???? ??????array[emptyIndex] = array[emptyIndex = i];
  • ???? ????}
  • ???? ??}???
  • ???? ??// 助手1和助手2相遇后會停止循環,將最初取出的基準值給最后的空位
  • ???? ??array[emptyIndex] = pivot;
  • ???? ???
  • ???? ??// =====本輪快速排序完成=====
  • ???? ??// 如果分割點i左側有2個以上的元素,遞歸調用繼續對其進行快速排序
  • ???? ??if (i - start > 1) {
  • ???? ????quickSort(array, 0, i - 1);
  • ???? ??}
  • ???? ??// 如果分割點j右側有2個以上的元素,遞歸調用繼續對其進行快速排序
  • ???? ??if (end - j > 1) {
  • ???? ????quickSort(array, j + 1, end);
  • ???? ??}
  • ???? }

?

算法優化:選取基準軸點時采用三數取中法:

public class Quick {

?? public void sort(int[] array){

????? int start=0;

????? int end=array.length-1;

????? quickSort(array,start,end);

?? }

?? public void quickSort(int[] array, int start, int end) {

????? // TODO Auto-generated method stub

????? int i=start;

????? int j=end;

????? int emptyIndex=start;

????? int pivot=middle3(array,start,end);

????? while(i<j){

???????? while(i<j&&array[j]>=pivot){

??????????? j--;

???????? }

???????? if(i<j)

??????????? array[emptyIndex]=array[emptyIndex=j];

???????? while(i<j&&array[i]<=pivot){

??????????? i++;

???????? }

???????? if(i<j)

??????????? array[emptyIndex]=array[emptyIndex=i];

????? }

????? array[emptyIndex]=pivot;

?????

????? if(i-start>1)

???????? quickSort(array,start,i-1);

????? if(end-j>1)

???????? quickSort(array,j+1,end);

?? }

?

2.8 計數排序算法(穩定,也是桶排序)

問題描述:對于一個int數組,請編寫一個計數排序算法,對數組元素排序。?
問題分析:

1. 提前必須是已知待排序的關鍵字為整型且范圍已知。?
2. 時間復雜度為O(n+k),n指的是桶的個數,k指的是待排序數組的長度,不是基于比較的排序算法,因此效率非常之高。?
3. 穩定性好,這個是計數排序非常重要的特性,可以用在后面介紹的基數排序中。?
4. 但需要一些輔助數組,如C[0..k],因此待排序的關鍵字范圍0~k不宜過大。

? ??public int[] countingSort(int[] A, int n) {

??????? if(A==null ||n<2){

??????????? return A;

??????? }

??????? //找出桶的范圍,即通過要排序的數組的最大最小值來確定桶范圍

??????? int min=A[0];

??????? int max=A[0];

??????? for(int i=0;i<n;i++){

??????????? min=Math.min(A[i],min);

??????????? max=Math.max(A[i],max);

??????? }

??????? //確定桶數組,桶的下標即為需排序數組的值,桶的值為序排序數同一組值出現的次數

??????? int[] arr = new int[max-min+1];

??????? //往桶里分配元素

??????? for(int i=0;i<n;i++){

??????????? arr[A[i]-min]++;

??????? }

??????? //從桶中取出元素

??????? int index=0;

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

??????????? while(arr[i]-->0){

??????????????? A[index++]=i+min;

??????????? }

??????? }

??????? return A;

??? }

}

?

2.9 基數排序算法(穩定)

問題描述:對于一個int數組,請編寫一個基數排序算法,對數組元素排序。?
問題分析:

基數排序(Radix sort)是一種非比較型整數排序算法,其原理是將整數按位數切割成不同的數字,然后按每個位數分別比較。由于整數也可以表達字符串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是只能使用于整數。將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然后,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以后,數列就變成一個有序序列。

鍵字范圍0~k不宜過大。

public void sort(int[] array){

????? int max=0;

????? int d=0;// 位數

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

???????? max=Math.max(max, array[i]);

????? }

????? while(max>0){

???????? max/=10;

???????? d++;

????? }

????? int t=0;

????? int m=1;

????? int n=1;

????? int[][] temp=new int[10][array.length];

????? int[] order=new int[10];

????? while(m<=d){

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

??????????????? int k=((array[i]/n)%10);

??????????????? temp[k][order[k]++]=array[i];

??????????? }

????????

???????? for (int i = 0; i < 10; i++) {

??????????? if(order[i]!=0){

??????????????? for (int j = 0; j <order[i]; j++) {

?????????????????? array[t++]=temp[i][j];

??????????????? }

??????????????? order[i]=0;

??????????? }

???????? }

???????? t=0;

???????? n=n*10;

???????? m++;

????? }

?? }

采用鏈表的方式來實現基數排序:?

//基數排序開始
public static void radixSort(int[] array){
int max=array[0];
for (int i = 0; i < array.length; i++) {
max=Math.max(max, array[i]);
}
int time=0;
while(max!=0){
time++;
max=max/10;
}
List<List<Integer>> list=new ArrayList<List<Integer>>();
for(int i=0;i<10;i++){
List<Integer> item=new ArrayList<Integer>();
list.add(item);
}

for (int i = 0; i < time; i++) {
for (int j = 0; j < array.length; j++) {
int index=array[j]%(int)Math.pow(10, i+1);
index/=(int)Math.pow(10, i);
list.get(index).add(array[j]);
}
int count=0;
for (List<Integer> a : list) {
for (int m : a) {
if(m!=0){
array[count++]=m;
}
}
a.clear();
}
}
}

//基數排序結束

?

轉載于:https://www.cnblogs.com/jetHu/p/6445060.html

總結

以上是生活随笔為你收集整理的九大排序算法Java实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。