排序算法-Elementary Sorts

85 阅读1分钟

Selection sort

public class Selection {
    public static void sort(Comparable[] a) 
    {
    int N = a.length; 
    for (int i = 0; i < N; i++) { 
        int min = i; // index of minimal entr. 
        for (int j = i+1; j < N; j++) 
            if (less(a[j], a[min])) min = j; 
        exch(a, i, min); 
        }
    }
}

每次遍历都要向后比较到最后一位

complexity

Selection sort uses ~N2/2 compares and N exchanges to sort an array of length N

Insertion sort

func InsertionSort(nums []int) []int {
   n := len(nums)

   if n <= 1 {
      return nums
   }

   for i := 1; i < n; i++ {
      //只要比前一个小则交换
      for j := i - 1; j >= 0 && nums[j+1] < nums[j]; j-- {
         swap(&nums, j+1, j)
      }
   }
   return nums
}

优化swap:

func InsertionSortV2(nums []int) []int {
   n := len(nums)

   if n <= 1 {
      return nums
   }

   for i := 1; i < n; i++ {
      curValue := nums[i]
      j := i - 1
      //只要比前一个小则交换
      for ; j >= 0 && curValue < nums[j]; j-- {
         nums[j+1] = nums[j]
      }

      nums[j+1] = curValue
   }
   return nums
}

每次与前一个相邻的比较,如果比前一个小则交换,否则比较终止

complexity

Insertion sort uses ~(N^2)/4 compares and ~(N^2)/4 exchanges to sort a randomly ordered array of length N with distinct keys, on the average. The worst case is ~(N^2)/2 compares and ~(N^2)/2 exchanges and the best case is N − 1 compares and 0 exchanges.

application

Insertion sort works well for certain types of nonrandom arrays:

1.already sorted

2.arrays whose keys are all equal

3.partially sorted array

• An array where each entry is not far from its final position

• A small array appended to a large sorted array

• An array with only a few entries that are not in place

Shellsort

Insertion sort is slow for large unordered arrays because the only exchanges it does involve adjacent entries, so items can move through the array only one place at a time. For example, if the item with the smallest key happens to be at the end of the array, N−1 exchanges are needed to get that one item where it belongs.

Shellsort is a simple extension of insertion sort that gains speed by allowing exchanges of array entries that are far apart, to produce partially sorted arrays that can be efficiently sorted, eventually by insertion sort.

The idea is to rearrange the array to give it the property that taking every hth entry (starting anywhere) yields a sorted subsequence. Such an array is said to be h-sorted. Put another way, an h-sorted array is h independent sorted subsequences, interleaved together. By h-sorting for some large values of h, we can move items in the array long distances and thus make it easier to h-sort for smaller values of h. Using such a procedure for any sequence of values of h that ends in 1 will produce a sorted array.(对h-sorted array做标准insertion sort时,每个元素移动位置不会超过h)

image.png 如图是h=3时的情况

We accomplish this task by using the insertion-sort code, but modified to decrement by h instead of 1 when moving through the array.

Shellsort gains efficiency by making a tradeoff between size and partial order in the subsequences. At the beginning, the subsequences are short; later in the sort, the subsequences are partially sorted. In both cases, insertion sort is the method of choice. The extent to which the subsequences are partially sorted is a variable factor that depends strongly on the increment sequence.

func ShellSort(nums []int) []int {
   n := len(nums)
   if n <= 1 {
      return nums
   }
   h := 1
   for ; h < n/3; h = 3*h + 1 {
   }

   for h >= 1 {
      for i := h; i < n; i++ {
         //每次比较的跨度为h ,
         //h也是sequence的个数,一开始 sequence 个数多,每个 sequence 的长度小
         //之后每次循环 sequence 个数/3 ,sequence 的长度*3
         curValue := nums[i]
         j := i - h
         for ; j >= 0 && curValue < nums[j]; j = j - h {
            nums[j+h] = nums[j]
         }
         nums[j+h] = curValue
      }
      h = h / 3
   }
   return nums
}

Shellsort is useful even for large arrays, particularly by contrast with selection sort and insertion sort. It also performs well on arrays that are in arbitrary order (not necessarily random).

complexity

the worst-case number of compares for ALGORITHM 2.3 is proportional to N^(3/2)

common function

func swap(nums *[]int, i int, j int) {
   tmp := (*nums)[j]
   (*nums)[j] = (*nums)[i]
   (*nums)[i] = tmp
}

参考: algs4.cs.princeton.edu/21elementar…