Classic sorting algorithm and summary (python implementation)

1. The basic concepts and classification of sorting

The so-called sorting is to make a series of records, according to the size of one or some keywords, the operation of increasing or decreasing. Sorting algorithm is how to make the records arranged in accordance with the requirements.

Sorting stability:

After some sorting, if the two records have the same serial number and the order of the two records in the original unordered records remains unchanged, the sorting method used is said to be stable;

Inner and outer sorting

Internal sorting: During sorting, all records to be sorted are placed in memory.
External sorting: During sorting, external storage is used.
Usually the discussion is within sorting.

Three factors that affect the performance of the internal sorting algorithm:

  • Time complexity: ie time performance, the efficient sorting algorithm should have as few keyword comparisons and recorded movements as possible
  • Space complexity: mainly the auxiliary space required for executing the algorithm, the less the better
  • Algorithm complexity. Mainly refers to the complexity of the code.

According to the main operations used in the sorting process, the internal sorting can be divided into:

  • Insert sort
  • Exchange order
  • Select sort
  • Merge sort

According to the complexity of the algorithm, it can be divided into two categories:

  • Simple algorithm: including bubble sort, simple selection sort and direct insertion sort
  • Improved algorithm: including Hill sort, heap sort, merge sort and quick sort

The following seven sorting algorithms are just the most classic ones among all sorting algorithms, but not all.

2. Bubble Sort BubbleSort

Introduction:

The principle of bubble sort is very simple. It repeatedly visits the sequence to be sorted, compares two elements at a time, and exchanges them if their order is wrong.

step:

  1. Compare adjacent elements. If the first one is bigger than the second one, swap them both.
  2. Do the same for the 0th to n-1th data. At this time, the largest number "floats" to the last position of the array.
  3. Repeat the above steps for all elements except the last one.
  4. Continue to repeat the above steps for fewer and fewer elements each time until there are no pairs of numbers to compare.

Python implementation

def bubble_sort(arr):
    n = len(arr)
    # 遍历所有数组元素
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:		#如果前者比后者大
                arr[j], arr[j + 1] = arr[j + 1], arr[j]		 #则交换两者
    return print(arr)

arr = [64, 34, 25, 12, 22, 11, 90]

bubble_sort(arr)

3. Selection sorting SelectionSort

Introduction:

Selection sorting is undoubtedly the simplest and most intuitive sorting. It works as follows.

step:

  1. Find the smallest (large) element in the unsorted sequence and store it at the beginning of the sorted sequence.
  2. Then continue to find the smallest (large) element from the remaining unsorted elements, and then put it at the end of the sorted sequence.
  3. And so on, until all elements are sorted.

Python implementation

def select_sort(arr):
    n = len(arr)
    for i in range(n):
        min = i  # 最小元素下标标记
        for j in range(i + 1, n):
            if arr[j] < arr[min]:
                min = j  # 找到最小值的下标
        arr[min], arr[i] = arr[i], arr[min]  # 交换两者
    return print(arr)

arr = [64, 34, 25, 12, 22, 11, 90]
select_sort(arr)

4. Insert Sort InsertionSort

Introduction:

The working principle of insertion sorting is that for each unsorted data, it scans from back to front in the sorted sequence, finds the corresponding position and inserts.

step:

  1. Starting from the first element, the element can be considered to have been sorted
  2. Take the next element and scan from back to front in the sequence of sorted elements
  3. If the scanned element (sorted) is larger than the new element, move the element back one bit
  4. Repeat step 3 until you find the position of the sorted element less than or equal to the new element
  5. After inserting the new element at this position
  6. Repeat steps 2 ~ 5

Sorting demo:

img

Python implementation

def inset_sort(arr):
    n = len(arr)
    for i in range(1,n):
        if arr[i] < arr[i-1]:
            temp = arr[i]
            index = i  # 待插入的下标
            for j in range(i-1,-1,-1):   # 从i-1 循环到 0 包括0
                if arr[j] > temp:
                    arr[j+1] = arr[j]
                    index = j   # 记录待插入的下标
                else:
                    break
            arr[index] = temp
    return print(arr)

arr = [64, 34, 25, 12, 22, 11, 90]
inset_sort(arr)

5. Hill Sort ShellSort

Introduction:

Hill sorting, also called descending incremental sorting algorithm , is essentially grouping insertion sorting. Proposed by Donald Shell in 1959. Hill sorting is an unstable sorting algorithm.

The basic idea of ​​Hill sorting is to list the array in a table and insert and sort the columns separately. Repeat this process, but each time with a longer column (the step size is longer and the number of columns is less). . Finally, the entire table has only one column. The conversion of the array to the table is to better understand the algorithm, the algorithm itself still uses the array to sort.

For example, suppose there is such a set of numbers [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ], if we start sorting with a step size of 5, we can better describe the algorithm by placing this list in a table with 5 columns, so they should look like this:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

Then we sort each column:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

When the above four lines of numbers, we get together in sequence: [ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]. At this time, 10 has been moved to the correct position, and then sorted in steps of 3:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

After sorting it becomes:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

Finally, sort by 1 step (this is a simple insertion sort).

Python implementation

def shell_sort(ary):
    n = len(ary)
    gap = round(n/2)       #初始步长 , 用round四舍五入取整
    while gap > 0 :
        for i in range(gap,n):        #每一列进行插入排序 , 从gap 到 n-1
            temp = ary[i]
            j = i
            while ( j >= gap and ary[j-gap] > temp ):    #插入排序
                ary[j] = ary[j-gap]
                j = j - gap
            ary[j] = temp
        gap = round(gap/2)                     #重新设置步长
    return print(ary)
ary = [13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10]
shell_sort(ary)

6. Merge Sort MergeSort

Introduction:

The merge sort is a very typical application of the divide and conquer method. 归并The idea of ​​sorting is to 递归decompose the array first , and then merge the array.

First consider merging two ordered arrays. The basic idea is to compare the first number of the two arrays. Whoever is younger will take the first one, and after taking it, the corresponding pointer will move back one bit. Then compare again until one array is empty, and finally copy the rest of the other array.

Considering recursive decomposition, the basic idea is to decompose the array into a leftsum right. If the internal data of these two arrays is ordered, then the two arrays can be merged and sorted using the above method of merging arrays. How to make these two arrays internally ordered? It can be divided into two again until the decomposed group contains only one element. At this time, it is considered that there is order within the group. Then you can merge and sort the two adjacent groups.

Sorting demo:

img

Python implementation

def merge_sort(ary):
    if len(ary) <= 1:
        return ary
    num = int(len(ary) / 2)  # 二分分解
    left = merge_sort(ary[:num])
    right = merge_sort(ary[num:])
    return merge(left, right)  # 合并数组

def merge(left, right):
'''合并操作,
将两个有序数组left[]和right[]合并成一个大的有序数组
'''
l, r = 0, 0 # left与right数组的下标指针
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result

ary = [13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10]
merge_sort(ary)

7. Quick Sort

Introduction:
Quick sort is usually obviously faster than other algorithms with the same Ο (n log n) , so it is often used, and the quick sort uses the idea of divide and conquer , so in many written interviews, you can often see the quick sort shadow. It can be seen that the importance of mastering fast platoon.

step:

  1. Pick an element from the series as the base number.
  2. In the partitioning process, the ones larger than the reference number are placed on the right, and the numbers less than or equal to it are placed on the left.
  3. Then recursively perform the second step on the left and right intervals until each interval has only one number.

Sorting demo:

img

Python implementation

def quick_sort(ary):
    return qsort(ary, 0, len(ary) - 1)

def qsort(ary, left, right):
# 快排函数,ary为待排序数组,left为待排序的左边界,right为右边界
if left >= right:
return ary
key = ary[left] # 取最左边的为基准数
lp = left # 左指针
rp = right # 右指针
while lp < rp:
while ary[rp] >= key and lp < rp:
rp -= 1
while ary[lp] <= key and lp < rp:
lp += 1
ary[lp], ary[rp] = ary[rp], ary[lp]
ary[left], ary[lp] = ary[lp], ary[left]
qsort(ary, left, lp - 1)
qsort(ary, rp + 1, right)
return ary

ary = [13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10]
quick_sort(ary)

def quick_sort(a, start, end):
    if start < end:
        i, j = start, end  # 记录当前索引值
        base = a[i]  # 设置基准

        while i < j:
            while (i < j) and (a[j] >= base):
                j -= 1
            a[i] = a[j]

            while (i < j) and (a[i] <= base):
                i += 1
            a[j] = a[i]
        a[i] = base
        quick_sort(a, start, i - 1)
        quick_sort(a, j + 1, end)
    return print(a)


a = [13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10]
quick_sort(a, 0, len(a) - 1)

8. HeapSort

Introduction:

Heap sort is used frequently in top K problems. Heap sorting is implemented using a binary fork data structure, although it is essentially a one-dimensional array. Binary heap is an approximately complete binary tree.

Binary heap has the following properties:

  1. The key value of the parent node is always greater than or equal to (less than or equal to) the key value of any child node.
  2. The left and right subtrees of each node are a binary heap (both the largest heap or the smallest heap).

step:

  1. Build maximum heap (Build_Max_Heap): If the array subscript range is 0 ~ n, considering that a single element is a large root heap, then n/2the elements starting from the subscript are all large root heaps. Therefore, as long as the n/2-1big root heap is constructed in order from the beginning, this can ensure that when a node is constructed, its left and right subtrees are already big root heaps.
  2. Heap sort (HeapSort): Because the heap is simulated with an array. After getting a large root heap, the array is not ordered. Therefore, the heaped array needs to be ordered. The idea is to remove the root node and do the recursive operation of maximum heap adjustment. The first time heap[0]with the heap[n-1]exchange, and then to heap[0...n-2]do the maximum heap adjustment. The second will be heap[0]the heap[n-2]exchange, and then to heap[0...n-3]do the maximum heap adjustment. Repeat this operation until heap[0]and heap[1]exchange. Since the largest number is merged into the following ordered range each time, the entire array is ordered after the operation.
  3. Max heap adjustment (Max_Heapify): This method is provided for the above two procedures. The purpose is to adjust the child nodes at the end of the heap so that the child nodes are always smaller than the parent node.

Sorting demo:

img

Python implementation

def heap_sort(ary):
    n = len(ary)
    first = int(n / 2 - 1)  # 最后一个非叶子节点
    for start in range(first, -1, -1):  # 构造大根堆
        max_heapify(ary, start, n - 1)
    for end in range(n - 1, 0, -1):  # 堆排,将大根堆转换成有序数组
        ary[end], ary[0] = ary[0], ary[end]
        max_heapify(ary, 0, end - 1)
    return print(ary)

最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点

start为当前需要调整最大堆的位置,end为调整边界

def max_heapify(ary, start, end):
root = start
while True:
child = root * 2 + 1 # 调整节点的子节点
if child > end: break
if child + 1 <= end and ary[child] < ary[child + 1]:
child = child + 1 # 取较大的子节点
if ary[root] < ary[child]: # 较大的子节点成为父节点
ary[root], ary[child] = ary[child], ary[root] # 交换
root = child
else:
break

ary = [13, 14, 94, 33, 82, 25, 59, 94, 65, 23, 45, 27, 73, 25, 39, 10]
heap_sort(ary)

Performance comparison of seven sorting algorithms

The following is a comparison of the indicators of seven classic sorting algorithms:

img

  • If the to-be-sorted sequence is basically ordered, please use a simple algorithm directly, and do not use a complex improved algorithm.
  • Although merge sort and quick sort have high performance, they require more auxiliary space. In fact, it is to use space for time.
  • The fewer the number of elements in the sequence to be sorted, the more suitable is the simple sorting method; the greater the number of elements, the more suitable is the improved sorting algorithm.
  • Although simple selection sort is not good in terms of time performance, it has high performance in space utilization. It is particularly suitable for those sorts of elements with a small amount of data and a large amount of information in each piece of data.

Guess you like

Origin www.cnblogs.com/sq1995liu/p/12756319.html