C language implements exchange sorting algorithm (bubble sort, quick sort)

Sorting and Finding Algorithms Catalog

[C language to achieve insertion sort] Insertion sort (direct, half, two-way, Hill)

[Three classic searches] Three classic searches (jump, interpolation, Fibonacci)

[Three basic searches] Three basic searches (sequential, binary, and block)


Table of contents

 foreword

1. Bubble sort

1. Basic idea

2. Optimization

3. Expand

2. Quick Sort

1. Basic idea

2. Optimization

3. Code


 foreword

查找和排序是数据结构与算法中不可或缺的一环,是前辈们在算法道路上留下的重要且方便的一些技巧,学习这些经典的查找和排序也能让我们更好和更快的解决问题。在这个专栏中我们会学习六大查找和十大排序的算法与思想,而本篇将详细讲解其中的交换排序——冒泡排序和快速排序;

注意:本文中所有排序按照升序排序,降序只需要把逻辑反过来即可!


1. Bubble sort

1. Basic idea

For many students, bubble sorting is very familiar. The idea of ​​bubbling is: constantly compare and exchange two elements, the larger one is on the right, and the smaller one is on the left;

 There is an array {5, 1, 4, 2, 8, 4}

first round

  • arr[0] = 5 and arr[1] = 1 compare 5 > 1, exchange;
  • arr[2] = 4 and arr[1] = 5 compare 5 > 4, exchange;
  • arr[2] = 5 and arr[3] = 2 compare 5 > 2, exchange;
  • arr[3] = 5 and arr[4] = 8 compare 5 < 8, do not exchange;
  • arr[4] = 8 and arr[5] = 4 compare 8 > 4, exchange;

 

second round

  • Repeat the above steps starting from arr[1];


... ... until looping N - 1 times, the sorting ends;

#include <stdio.h>
#include<stdlib.h>

//冒泡排序
void bubbleSort(int a[], int n)
{
    //一共要扫描n-1趟
    for(int i = 0; i < n - 1; i++)
    {
        //用来比较 交换
        for(int j = 0; j < n - i - 1; j++)
        {
            if(a[j] > a[j + 1])
            {
                int temp = a[j + 1];
                a[j + 1] = a[j];
                a[j] = temp; 
            }
        }
    }
}

int main()
{
    int arr[] = {5, 1, 4, 2, 8, 4};
    int length = sizeof(arr) / sizeof(arr[0]);
    bubbleSort(arr, length);
    for(int i = 0; i < length; i++)
    {
        printf("%d", arr[i]);
    }
    system("pause");
    return 0;
}

Then here comes the question, question 1: Here we find that for this array, the whole or even stable order has been arranged in the second round of sorting , and the remaining cycles are equivalent to waste, so is there a way to Judging that the array is already ordered?

There is also such an array {4, 2, 1, 5, 6, 8}

Question 2: We found that the parts of {5, 6, 8} are already ordered, and we need to continue to compare the ordered parts , so can we determine the boundary between the ordered part and the disordered part?

2. Optimization

  • For problem 1, we can add a flag to indicate whether the array is in order: when there is no exchange in a certain round of sorting, the array can be considered to be in order;
  • For problem 2, we can record the index of the place where the last exchange occurred during the bubble sorting process, as shown in the figure below, index==1, and each subsequent sorting only needs to be from the first to the index;

 It is worth noting that no matter how to optimize, the worst-case time complexity is O(n^2), that is, the case where the array is reversed;

3. Expand

Although using stacks to implement bubble sorting may not have an application scenario in practice (and it is not necessary), but there may be interviews that require stacks or other structures to implement bubble sorting to test proficiency in algorithms and thinking, so Here also provides the idea of ​​using stacks to implement bubble sorting;

void bubbleSort(int a[], int n)
{
    //定义两个栈S1和S2
    stack<int>stk1, stk2;
    //将数组中的所有元素入栈S1
    for (int i = 0; i < n; i++)
    {
        stk1.push(a[i]);
    }
    //循环N次 每一次找出最大的元素(就像真冒泡一样 最大的元素浮在最上面)
    for (int i = 0; i < n; i++)
    {
        //如果S1不为空
        while (!stk1.empty())
        {
            //如果S2为空就把栈S1顶的元素入栈S2
            if (stk2.empty())
            {
                stk2.push(stk1.top());
                stk1.pop();
            }
            else
            {
                int temp = 0;//用于接收需要交换的元素
                if (stk1.top() < stk2.top())
                {
                    //如果S1的栈顶小于S2的栈顶 把S1的栈顶压在S2的栈顶下面
                    temp = stk2.top();
                    stk2.pop();
                    stk2.push(stk1.top());
                    stk1.pop();
                    stk2.push(temp);
                }
                else
                {
                    stk2.push(stk1.top());
                    stk1.pop();
                }
            }
        }
        //把最大的元素从后往前更新回原数组中
        a[n - i - 1] = stk2.top();
        stk2.pop();
        //把剩下的元素倒栈 重复
        for (int j = stk2.size(); j > 0; j--)
        {
            stk1.push(stk2.top());
            stk2.pop();
        }
    }
}

2. Quick Sort

1. Basic idea

  • Select a benchmark (it can be considered as the element to be placed in the correct position after sorting, it can be the first element, the last one in the middle, as long as the benchmark is the maximum value in the left collection and the smallest in the right collection value);
  • Make a division of the elements in the array, and each division will put the value x as the reference in the correct position of the sorted array, and put all the values ​​smaller than x on the left and those larger than x on the right;

There is an array {1, 8, 3, 9, 4, 5, 4, 7}

Assuming that the element arr[7] = 7 is selected as the benchmark, it is to put 7 in the correct position, then there are only two situations:

Either the 7 itself is the correct position, or it is just ahead;

Step 1: Initialize the pointer i = -1, j = 0, compare the element pointed to by j with 7, when 1 < 7, exchange i++ with the elements pointed to by i and j, j++;

Step 2: Compare the element pointed to by j with 7, when 8 > 7, use j++;

Step 3: Compare the element pointed to by j with 7, when 3 < 7, exchange i++ with the elements pointed to by i and j, j++;

Step 4: Compare the element pointed to by j with 7, and when 4 < 7, exchange i++ with the elements pointed to by i and j, j++;

Step 5: Compare the element pointed to by j with 7, when 5 < 7, exchange i++ with the elements pointed to by i and j, j++;

Step 5: Compare the element pointed to by j with 7, and when 4 < 7, exchange i++ with the elements pointed to by i and j, j++;

Step 6: When the traversal from j to 7 ends, exchange the position of i++ with 7, and the first sorting ends;

In this way, benchmark 7 finds its correct position in the array, and divides the array into two sides [0, 5) and (5, 7]. At this time, select another benchmark and perform the above steps, as shown in the figure below : 

Do you feel familiar? Yes, this is a binary tree:

2. Optimization

Since it is a binary tree, it is naturally the worst case to discharge a slanted tree; to alleviate this problem, the intermediate value can be used as a benchmark to reduce the occurrence of this situation;

  • That is, the complexity is related to the length of the array and the selection of the benchmark. The tail benchmark is O(n^2) because each division of n times requires O(n), while the balanced tree is O(nlogn), which can be optimized by mathematical methods The benchmark selection , but no matter what benchmark is chosen, it should be able to satisfy: the left side of the benchmark is small, and the right side is large;

As we said before, quick sort is actually an unstable sort (unstable sort means that there are many exchanges, and if you need to sort by multiple conditions, it will be chaotic), and we also said that any unstable sorting algorithm is There is a way to make it stable , using the idea of ​​exchanging space for time ;

  • That is, we can use a variable to mark the original order;

3. Code

Since the number of comparisons is reduced by continuously dividing the array, it is known that the idea of ​​​​divide and conquer is used , that is, the code can be implemented with recursion :

#include <stdio.h>
#include<stdlib.h>

//快排
void quickSort(int a[], int low, int high)
{
   if(low < high)
   {
        int i = low;//这里以i下标的值为基准
        int j = high;
        int k = a[low];//k是用来记录基准的值
        while(i < j)
        {
            //从右往左找第一个比k要小的值
            while(i < j && a[j] >= k)
            {
                j--;
            }
            if(i < j)
            {
                a[i++] = a[j];
            }
            //从左往右找第一个比k要大的值
            while(i < j && a[i] < k)
            {
                i++;
            }
            if(i < j)
            {
                a[j--] = a[i];
            }
        }
        a[i] = k;
        //递归
        quickSort(a, low, i - 1);
        quickSort(a, i + 1, high);
   }
}

int main()
{
    int arr[] = {1, 8, 3, 9, 4, 5, 4, 7};
    int length = sizeof(arr) / sizeof(arr[0]);
    quickSort(arr, 0, length - 1);
    for(int i = 0; i < length; i++)
    {
        printf("%d ", arr[i]);
    }
    system("pause");
    return 0;
}

operation result

Guess you like

Origin blog.csdn.net/ZER00000001/article/details/125636942