Sort-Swap Sort-Quick Sort

Quick sort

Quick Sort is improved from bubble sort . In the bubble sort process, only two adjacent records are compared, so each time two adjacent records are exchanged, only one reverse order can be eliminated. If multiple reverse orders can be eliminated through one exchange of two (partially adjacent) records, the sorting speed will be greatly accelerated. A single swap in the quicksort method may eliminate multiple reversals.

Algorithm ideas

[Algorithm steps]

Select any element in the list to be sorted L[1...n] as the pivot (or fulcrum, benchmark, usually the first element), set its key to pivotKey, and after one sorting, all keys smaller than Swap the records with pivotKey to the front, and swap all records with keys greater than pivotKey to the back. As a result, the record table to be sorted is divided into two sub-tables, and finally the pivot is placed at the dividing point. Then, perform quick sort on the left and right subtables respectively until each subtable has only one record, and the sorting is completed.

Among them, the specific steps of a quick queue are as follows:
① Select the first record in the table to be sorted as the pivot, and temporarily store the pivot record at the position r[0]. There are two pointers, low and high, which initially point to the lower and upper bounds of the table respectively (on the first pass, low=0, high=L.length).
② Search left from the rightmost position of the table, find the first record with a keyword smaller than the pivot keyword pivotKey, and move it left to low.
The specific operation is: when low < high, if the key of the record pointed to by high <= pivotKey, move the pointer high (high–) to the left; otherwise, exchange the record pointed by high with the pivot record.
③ Then search to the right from the leftmost position of the table to find the first keyword <= pivotKey, then move low(lwo++) to the right; otherwise, the record pointed to by low is exchanged with the pivot record.
④ Repeat steps ② and ③ until low and high are equal. At this time, the position of lwo or high is the final position of the pivot in this sorting, and the original table is divided into two sub-tables.

In the above process, the exchange of records occurs with the pivot. Each exchange requires moving the record 3 times. You can temporarily store the pivot at the position r[0]. During the sorting process, only the records to be moved are moved with the pivot. The records of axis exchange only move r[low] or r[high] in one direction until the pivot record is moved to the correct position after a sorting pass.

Algorithm implementation

Define the linear table structure for storing records

//记录
typedef struct ElemType{
    
    
    int key;
    string info;
}ElemType;

#define InitSize 50
typedef struct {
    
    
    ElemType data[InitSize];
    int length;
}SqList;

void toString(SqList L);

void toString(SqList L,int low,int high);

void InitSqList(SqList &L);

Code

int amount = 0;
void QuickSort(SqList &L, int low, int high) {
    
    
//  初始调用 low = 1;high=L.length;
    cout << "-------------------------第  " << ++amount << "次趟排序,low="<<low<<",high="<<high <<"-------------------------------"<< endl;
    toString(L,low,high);
    if (low < high) {
    
     //子表长度大于1
        int pivotLoc = partition(L, low, high); //将L.r[low...high]一分为二,pivotLoc时枢轴的位置
        cout << "当前结果:"<< endl;
        toString(L);
        QuickSort(L, low, pivotLoc - 1); //对左子表递归排序
        QuickSort(L, pivotLoc + 1, high);//对右子表递归排序
    }
}
int partition(SqList &L, int low, int high) {
    
    
    L.data[0] = L.data[low]; //用子表的第一个记录做枢轴记录
    int pivotKey = L.data[0].key;
    cout << " 当前枢轴key=  " << pivotKey << endl;
    while (low < high) {
    
    
        while (low < high && L.data[high].key >= pivotKey) --high; //从右向左,找到第一个>=pivotKey的记录
        L.data[low] = L.data[high]; //比枢轴小的记录移动到低位
        cout << " r[" << high <<"].key("<<L.data[high].key<<")>= pivotKey(" << pivotKey << ") 移动到低位 *" << low << "\t";
        toString(L);
        while (low < high && L.data[low].key <= pivotKey) ++low;//从左向右,找到第一个<=pivotKey的记录
        L.data[high] = L.data[low];//比枢轴大的记录移动到高位
        cout << " r[" << low << "].key("<<L.data[low].key<<")<= pivotKey(" << pivotKey << ") 移动到高位 *" << high << "\t";
        toString(L);
    }
    L.data[low] = L.data[0]; //将枢轴放置到正确的位置
    cout << " 枢轴的正确位置:" << low << endl;
    return low;
}

Test Case

void testQuickSort() {
    
    
    SqList L;
    InitSqList(L);
    cout <<" ----------------------------------初始 L---------------------------------------- "<< endl;
    toString(L);
    QuickSort(L,1,L.length);
    cout <<" --------------------------------最终排序结果--------------------------------------- "<< endl;
    toString(L,1,L.length);
}
int main() {
    
    
    testQuickSort();
    return 0;
}

Test Results

 ----------------------------------初始 L---------------------------------------- 
key  [ 0 41 67 34 0 69 24 78 58 62 64 ]
-------------------------1次趟排序,low=1,high=10-------------------------------
待排序子表 [ 41 67 34 0 69 24 78 58 62 64 ]
 当前枢轴key=  41
 r[6].key(24)>= pivotKey(41) 移动到低位 *1	key  [ 41 24 67 34 0 69 24 78 58 62 64 ]
 r[2].key(67)<= pivotKey(41) 移动到高位 *6	key  [ 41 24 67 34 0 69 67 78 58 62 64 ]
 r[4].key(0)>= pivotKey(41) 移动到低位 *2	key  [ 41 24 0 34 0 69 67 78 58 62 64 ]
 r[4].key(0)<= pivotKey(41) 移动到高位 *4	key  [ 41 24 0 34 0 69 67 78 58 62 64 ]
 枢轴的正确位置:4
当前结果:
key  [ 41 24 0 34 41 69 67 78 58 62 64 ]
-------------------------2次趟排序,low=1,high=3-------------------------------
待排序子表 [ 24 0 34 ]
 当前枢轴key=  24
 r[2].key(0)>= pivotKey(24) 移动到低位 *1	key  [ 24 0 0 34 41 69 67 78 58 62 64 ]
 r[2].key(0)<= pivotKey(24) 移动到高位 *2	key  [ 24 0 0 34 41 69 67 78 58 62 64 ]
 枢轴的正确位置:2
当前结果:
key  [ 24 0 24 34 41 69 67 78 58 62 64 ]
-------------------------3次趟排序,low=1,high=1-------------------------------
待排序子表 [ 0 ]
-------------------------4次趟排序,low=3,high=3-------------------------------
待排序子表 [ 34 ]
-------------------------5次趟排序,low=5,high=10-------------------------------
待排序子表 [ 69 67 78 58 62 64 ]
 当前枢轴key=  69
 r[10].key(64)>= pivotKey(69) 移动到低位 *5	key  [ 69 0 24 34 41 64 67 78 58 62 64 ]
 r[7].key(78)<= pivotKey(69) 移动到高位 *10	key  [ 69 0 24 34 41 64 67 78 58 62 78 ]
 r[9].key(62)>= pivotKey(69) 移动到低位 *7	key  [ 69 0 24 34 41 64 67 62 58 62 78 ]
 r[9].key(62)<= pivotKey(69) 移动到高位 *9	key  [ 69 0 24 34 41 64 67 62 58 62 78 ]
 枢轴的正确位置:9
当前结果:
key  [ 69 0 24 34 41 64 67 62 58 69 78 ]
-------------------------6次趟排序,low=5,high=8-------------------------------
待排序子表 [ 64 67 62 58 ]
 当前枢轴key=  64
 r[8].key(58)>= pivotKey(64) 移动到低位 *5	key  [ 64 0 24 34 41 58 67 62 58 69 78 ]
 r[6].key(67)<= pivotKey(64) 移动到高位 *8	key  [ 64 0 24 34 41 58 67 62 67 69 78 ]
 r[7].key(62)>= pivotKey(64) 移动到低位 *6	key  [ 64 0 24 34 41 58 62 62 67 69 78 ]
 r[7].key(62)<= pivotKey(64) 移动到高位 *7	key  [ 64 0 24 34 41 58 62 62 67 69 78 ]
 枢轴的正确位置:7
当前结果:
key  [ 64 0 24 34 41 58 62 64 67 69 78 ]
-------------------------7次趟排序,low=5,high=6-------------------------------
待排序子表 [ 58 62 ]
 当前枢轴key=  58
 r[5].key(58)>= pivotKey(58) 移动到低位 *5	key  [ 58 0 24 34 41 58 62 64 67 69 78 ]
 r[5].key(58)<= pivotKey(58) 移动到高位 *5	key  [ 58 0 24 34 41 58 62 64 67 69 78 ]
 枢轴的正确位置:5
当前结果:
key  [ 58 0 24 34 41 58 62 64 67 69 78 ]
-------------------------8次趟排序,low=5,high=4-------------------------------
待排序子表 [ ]
-------------------------9次趟排序,low=6,high=6-------------------------------
待排序子表 [ 62 ]
-------------------------10次趟排序,low=8,high=8-------------------------------
待排序子表 [ 67 ]
-------------------------11次趟排序,low=10,high=10-------------------------------
待排序子表 [ 78 ]
 --------------------------------最终排序结果--------------------------------------- 
待排序子表 [ 0 24 34 41 58 62 64 67 69 78 ]

进程已结束,退出代码0

Analysis of Algorithms

① Time complexity:

It can be seen from the recursion tree of the quick sort algorithm that the number of quick sort passes depends on the depth of the recursion tree.

  • Best case scenario:

After each sorting pass, the records can be evenly divided into two sub-tables of approximately equal length, similar to a half search. In a sequence of n elements, the time required to position the pivot is O(n). If T(n) is the time required to sort a sequence of n elements, and each time the pivot is correctly positioned, the sequence is divided into two sublists of equal length. At this time, let Cn be a constant. , indicating the time for a quick sort of n elements, then the total sorting time is

    T(n) = Cn +2T(n/2)
          <= n+2T(n/2)
          <= n+2T(n/2+2T(n/4)) = 2n+4T(n/4)
          <= 2n+4(n/4+2T(n/8)) = 3n+8T(n/8)
          ....
          <= kn+2^kT(n/2^k)
          ∵ k=log2n
          ∴ T(n)≤ nlog2n +nT(1) ≈ O(nlog2n)
  • Worst case scenario:

When the sequence to be sorted has been sorted, its recursive tree becomes a single-branch tree, and each division only results in a subsequence that is one record less than the last time.
In this way, n-1 passes are required to locate all records, and the i-th pass requires ni comparisons. In this way, the total number of keyword comparisons KCN is

KCN=(n-1)+(n-2)+....+(3-1)+(2-1) 
   =n(n-1)/2 ≈ n^2/2

In this case, the speed of quick sort has degraded to the level of simple sort. Reasonable selection of the pivot can avoid this worst-case scenario, such as using the rule of "finding the middle of the three": comparing the keywords of the first record, the last record and the middle record in the current table, and centering the keywords The record is used as a pivot record, swapped to the position of the first record beforehand.
It can be theoretically proven that, on average, the time complexity of quick sort isO(nlog2n)

② Space complexity

Quick sort is recursive and requires a stack to store corresponding data during execution. The maximum number of recursive calls is consistent with the depth of the recursion tree, soThe space complexity is O(nlog2n) in the best case and O(n) in the worst case.

[Algorithm Features]

① The sorting method caused by recording non-sequential movements isunstable.
② During the sorting process, it is necessary to locate the lower bound and upper bound of the table, soSuitable for sequential structures, difficult to use for chain structures.
③ When n is large, on average, quick sort is allinternalIn sorting methodfastestof a kind, so it is suitable forThe initial records are out of order and n is largesituation at the time.

Guess you like

Origin blog.csdn.net/QQ657205470/article/details/127747109