数据结构算法基础-内部排序算法

Posted vincentbnu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构算法基础-内部排序算法相关的知识,希望对你有一定的参考价值。

技术分享图片
 1 arr = [1,23,12,9,8,8,9,1,1,8,]
 2 def quickSortCore(arr,start,end):
 3     if start < end:
 4         index = partition(arr,start,end)
 5         quickSortCore(arr,start,index-1)
 6         quickSortCore(arr,index+1,end)
 7 
 8 def partition(arr,start,end):
 9     key = arr[start]
10     while(start < end):
11         while(start < end  and key <= arr[end]):
12             end -= 1
13         if(start < end):
14             arr[start],arr[end] = arr[end],arr[start]
15         while(start < end and key >= arr[start]):
16             start += 1
17         if(start<end):
18             arr[start],arr[end] = arr[end],arr[start]
19     return start
20 quickSortCore(arr,0,len(arr)-1)
21 print(arr)
View Code
技术分享图片
 1 package com.sort;
 2 
 3 public class QuickSortDemo {
 4     public static void main(String[] args) {
 5         int []arr = {8,9,8,8,9,1,1};
 6         QuickSortDemo q = new QuickSortDemo();
 7         q.quickSortCore(arr,0,arr.length-1);
 8         for(int a : arr){
 9             System.out.print(a+" ");
10         }
11     }
12     private void quickSortCore(int[] arr, int start, int end) {
13        if(start<end){
14            int sepIndex = partition(arr,start,end);
15 //           System.out.println(sepIndex);
16            quickSortCore(arr, start, sepIndex-1);
17            quickSortCore(arr, sepIndex+1, end);
18        }
19         
20     }
21     //分开
22     private int partition(int[] arr, int start, int end) {
23        int key = arr[start];
24        int tmp = 0;
25        while(start < end){
26            while((start < end) &&(key<= arr[end]) ){
27                end --;
28            }
29            // 交换时,一定是 start 与 end 相交换
30            if(start<end){ 
31                tmp = arr[end];
32                arr[end] = arr[start];
33                arr[start] = tmp;
34                start++;
35            }
36            while((start< end) &&(key>= arr[start])){
37                start++;
38            }
39            if(start<end){
40                tmp = arr[start];
41                arr[start] = arr[end];
42                arr[end] = tmp;
43                end--;
44            }
45        }// start == end
46 //       arr[start] = key;// 可不加
47         return start;
48     }
49 
50 }
View Code

注意:1) 交换时是 start 与 end 相交换,与 key是无关的。以上的代码应是最慢的quickSort; 2) 快排是不稳定的排序方法,空间复杂度为O(logN)

2、归并排序(稳定的排序方法,空间复杂度为O(n))

技术分享图片
 1 package com.sort;
 2 
 3 import java.util.Arrays;
 4 
 5 public class MergSortDemo {
 6     public static void main(String[] args) {
 7         int[] arr = { 8, 9, 8, 8, 9, 1, 1 };
 8         MergSortDemo m = new MergSortDemo();
 9         m.mergeSort(arr);
10         System.out.println(Arrays.toString(arr));
11     }
12 
13     public void mergeSort(int[] arr) {
14         int[] tmp = new int[arr.length];
15         mergeSortCore(arr, 0, arr.length - 1, tmp);
16     }
17 
18     public void mergeSortCore(int[] arr, int start, int end, int[] tmp) {
19         
20         if (start < end) {
21             int mid = (end - start) / 2 + start;
22             mergeSortCore(arr, start, mid, tmp);
23             mergeSortCore(arr, mid+1, end, tmp);
24             merge(arr, start, mid , end);
25         }
26     }
27 
28     // / arr[start...mid] 与 arr[mid+1,... end] ; 两个有序的子数组进行归并
29     private void merge(int[] arr, int start, int mid, int end) {
30         int s = start;
31         int m = mid + 1;
32 //        int e = end;
33         int[] tmp = new int[end - start + 1];
34         int index = 0;
35         // 处理共同的
36         while (s <= mid && m <= end) {
37             while (s <= mid && arr[s] <= arr[m]) {
38                 tmp[index++] = arr[s++];
39             }
40             while (m <= end && arr[s]> arr[m]) {
41                 tmp[index++] = arr[m++];
42             }
43         }
44         // 处理剩下的
45         while (s <= mid) {
46             tmp[index++] = arr[s++];
47         }
48         while (m <= end) {
49             tmp[index++] = arr[m++];
50         }
51         for (int i = start, j = 0; i <= end; i++) {
52             arr[i] = tmp[j++];
53         }
54     }
55 
56 }
View Code
技术分享图片
 1 def mergeSort(arr,start,end):
 2     if start > end:
 3         return
 4     if(start < end):
 5         mid = (end - start)//2 + start
 6         mergeSort(arr,start,mid)
 7         mergeSort(arr,mid+1,end)
 8         merge(arr,start,mid,end)
 9 
10 def merge(arr,start,mid,end):
11      # i =start,j = mid+1  ## python 中千万不要这样赋值!!
12      i = start
13      j = mid + 1
14      # print(str(start) + ‘..‘+ str(end))
15      tmp = []
16      while(i<=mid and j<=end):
17          if(arr[i] <= arr[j]):
18              tmp.append(arr[i])
19              i = i+1
20          else:
21              tmp.append(arr[j])
22              j = j + 1
23      if(i<= mid):
24          tmp.extend(arr[i:mid+1])
25      if(j <= end):
26         tmp.extend(arr[j:end+1])
27      arr[start:end+1] = tmp
28      del tmp
29      return arr
30 mergeSort(arr,0,len(arr)-1)
31 # merge(arr,0, (len(arr)-1)//2, len(arr)-1)
32 print(arr)
View Code

3、堆排序(不是稳定的排序方法)(下期)

 

 

扩展:

1)求数组中第K小的数

思想:利用快排的思想,随机选择元素 t , 它将数组分成两部分,小于 t 的 和大于 t 的; 分别计为 a[0...m-1] ; a[m+1,...n-1]

若  m = k -1 ;则返回 t ; 

若 m> k-1 ,说明 第k小的值在a[0...m-1];则求a[0...m-1]中第K小的值;

若 m< k-1 ,说明 第k小的值在a[m+1,...n-1],则在a[m+1,...n-1] 求 k-m小的数。 //  在代码中应是与 下标相比较,所以左右都是K,都是K

平均时间复杂度O(N)

技术分享图片
 1 def getKthSmall(arr,start,end,k):
 2     s = start
 3     e = end
 4     key = arr[s]
 5     while(s <  e):
 6         while(s < e and key <= arr[e]):
 7             e -= 1
 8         if key > arr[e]:
 9             arr[s] ,arr[e] = arr[e], arr[s]
10         while(s < e and key > arr[s]):
11             s += 1
12         if key < arr[s]:
13             arr[s], arr[e] = arr[e], arr[s]
14     print(start = %d;  end = %d  s = %d % (start, end,s))
15     if s == k-1:
16         return s
17     elif s > k-1:
18         return getKthSmall(arr,start,s-1,k)
19     else:
20         ## getKthSmall(arr,s+1,end, k-s-1), 不是这个,不是这个,不是这个,
21         ## 因为 我们是与下标比较,所以都是K,
22         return getKthSmall(arr,s+1,end,k)
23 
24 arr = [33,3,4,6,32]
25 index = getKthSmall(arr,0,len(arr)-1,3)
26 print(arr[index])
View Code

2) 求数组中的逆序数问题

给定一个数组A[0,...N-1] ,若对于两个元素a[i],a[j] ,若 i<j  且 a[i] >a[j] ,则称(a[i],a[j])为逆序对。

如数组 2,56,2,7的逆序数为 3. 归并排序图解如下,在合并时,都可用来计算其逆序对的数。

技术分享图片

技术分享图片

技术分享图片
 1 package com.sort;
 2 
 3 public class 逆序对数 {
 4     static Integer count = 0;
 5     public static void main(String[] args) {
 6         int[] arr = { 3, 56, 2, 7 };
 7         mergeSort(arr, 0, arr.length - 1);
 8         System.out.println(count);
 9     }
10 
11     private static void mergeSort(int[] arr, int start, int end) {
12         if (start < end) {
13             int mid = (end - start) / 2 + start;
14             mergeSort(arr, start, mid);
15             mergeSort(arr, mid + 1, end);
16             merge(arr, start, mid, end);
17         }
18     }
19 
20     private static void merge(int[] arr, int start, int mid, int end) {
21 //        System.out.println(".......2............");
22         int i = start, j = mid + 1;
23         int k = 0;
24         int[] tmp = new int[end - start + 1];
25         while (i <= mid && j <= end) {
26             if (i <= mid && arr[i] < arr[j]) {  // if (i <= mid && arr[i] <= arr[j])
27                 tmp[k++] = arr[i++];
28             }else{                                 // if (j <= end && arr[i] > arr[j])
29                 count += (mid - i + 1);           // 主要在这一块地方求!!,别注意条件,前没有=,
30                                                  //这也很好理解,有等于号,也是有逆序数对的。
31                 tmp[k++] = arr[j++];
32                 
33             }
34         }
35         while (i <= mid) {
36             tmp[k++] = arr[i++];
37         }
38         while (j <= end) {
39             tmp[k++] = arr[j++];
40         }
41         k = 0;
42         for (int t = start; t <= end; t++) {
43             arr[t] = arr[k++];
44         }
45 //        System.out.println("..================............");
46     }
47 
48 }
View Code

 

 即,如下图所示,在求 逆序对时,两个有序合并时, count  += (mid- i + 1);另要注意  arr[i]  等于 arr[j]  时,也是有逆序对的。注意 判断的条件!!

 

 

 

 

附其它O(n**2)的排序算法

直接插入排序(稳定的排序方法):

技术分享图片
 1 def straightInsertSort(arr):
 2     for i in range(1,len(arr)): ## [1,....len(arr)-1 ]个元素
 3         tmp = arr[i]
 4         j = i -1
 5         while j>=0 : ## 与 [i-1,....0]号元素相比较
 6             if(arr[j]> tmp):
 7                 arr[j+1] = arr[j]
 8                 j = j-1
 9             else:
10                 break
11         ## 跳出时 j==0 或 arr[j] <= tmp
12         arr[j+1] = tmp
View Code

 下期:堆排序,桶排序的运用

参考:

 

以上是关于数据结构算法基础-内部排序算法的主要内容,如果未能解决你的问题,请参考以下文章

重温基础算法内部排序之插入排序法

重温基础算法内部排序之简单插入排序法

数据结构算法基础-内部排序算法

重温基础算法内部排序之希尔排序法

重温基础算法内部排序之归并排序法

重温基础算法内部排序之归并排序法