[Data structure] exchange sort

1. Bubble
sort 1st pass: compare two adjacent data elements (i = 0, 1, 2,..., n-2) in turn, if array[i]>array[i+1], then exchange two Elements, otherwise they will not be exchanged, so that the data element with the largest value will be prevented from being in a[n-1];
pass 2: the number of data is reduced by 1, that is, the number of data elements is n-1, the operation method is similar to 1, After sorting, the next largest element in the data sequence is stored in array[n-2];
when n-1 times are over, the sorting ends.
write picture description here
The implementation code is as follows:

void BubbleSort(int *array, int size)
{
    assert(array || size < 0);
    int i = 0;
    int j = 0;
    for (; i < size - 1; ++i)
    {
        for (j = 0; j < size - i - 1; ++j)
        {
            if (array[j] > array[j + 1])
            {
                swap(array[j], array[j + 1]);
            }
        }
    }
}

Of course, from the above program, we can see that the efficiency of this program is very low, it needs O(N^2) time complexity, when the elements are already in order, he will still compare so many times, Therefore, we need to optimize the program in the next step. After a circle is compared, if the elements are in order, that is, there is no exchange, then terminate the program and exit directly.

void BubbleSort(int *array, int size)
{
    assert(array || size < 0);
    int i = 0;
    int j = 0;
    for (; i < size - 1; ++i)
    {
        bool flag = false;
        for (j = 0; j < size - i - 1; ++j)
        {
            if (array[j] > array[j + 1])
            {
                flag = true;
                swap(array[j], array[j + 1]);
            }
        }
        if (flag == false)
            break;
    }
}

Second, quick sort
(1) before and after the pointer method
write picture description here

The code is implemented as follows:

int Partition1(int*array, int left, int right)
{
    int key = right;
    int begin = left;
    int end = right;
    while (begin < end)
    {
        while (begin < end && array[begin] <= array[key])//此处加等于的原因是:如果碰到相等的元素,不论是拍到左边还是右边是没有影响的
        {
            ++begin;
        }
        while (begin < end && array[end] >= array[key])
        {
            --end;
        }
        if (begin != end)
            swap(array[begin], array[end]);
    }
    //两个指针相遇的时候,交换相遇的地方与最后一个元素,即基准值
    if (begin != key)
    {
        swap(array[begin], array[key]);
    }
    return begin;
}
//注意递归调用时的区间问题
void QuickSort(int *array, int left, int right)
{
    assert(array || left < 0 || right < 0);
    /*if (left >= right)
    {
        return;
    }*/
    if (left < right)
    {
        int div = Partition1(array, left, right);
        QuickSort(array, left, div - 1);//对划分出来的左半部分进行排序
        QuickSort(array, div + 1, right);//对划分出来的右半部分进行排序
    }
}

(2) Digging pit method The
pit digging method is similar to the left and right pointer method above, but each time you compare, you can use the current element to fill the previous pit.
write picture description here
The code implementation is as follows:

int Partition2(int*array, int left, int right)
{
    int key = array[right];//将基准值保存
    int begin = left;
    int end = right;
    while (begin < end)
    {
        while (begin < end && array[begin] <= key)
            ++begin;
        //填坑
        if (begin < end)
        {
            array[end] = array[begin];
        }

        while (begin < end && array[end] >= key)
            --end;

        if (begin < end)
        {
            array[begin] = array[end];
        }

    }
    //begin与end相遇,则用基准值去填充这个坑
    if (begin == end)
    {
        array[begin] = key;
    }
    return begin;
}
//递归调用
void QuickSort(int *array, int left, int right)
{
    assert(array || left < 0 || right < 0);
    /*if (left >= right)
    {
        return;
    }*/
    if (left < right)
    {
        int div = Partition2(array, left, right);
        QuickSort(array, left, div - 1);//对划分出来的左半部分进行排序
        QuickSort(array, div + 1, right);//对划分出来的右半部分进行排序
    }
}

(3) Front and rear pointer method
write picture description here

The code implementation is as follows:

int Partition3(int*array, int left,int right)
{
    int key = array[right];
    int cur = 0;
    int pre = cur - 1;
    while (cur < right)
    {
        while (cur < right&&array[cur] >= key)
        {
            ++cur;
        }
        if (cur < right&&++pre != cur)//如果cur中的值小于key,已经让pre走了一步
        {
            swap(array[pre], array[cur]);
        }
        ++cur;//让cur走到下一个位置,从而开始新的一轮的比较
    }
    ++pre;
    swap(array[pre], key);
    return pre;
}
//[  ]闭区间
void QuickSort(int *array, int left, int right)
{
    assert(array || left < 0 || right < 0);
    /*if (left >= right)
    {
        return;
    }*/
    if (left < right)
    {
        int div = Partition3(array, left, right);
        QuickSort(array, left, div - 1);//对划分出来的左半部分进行排序
        QuickSort(array, div + 1, right);//对划分出来的右半部分进行排序
    }
}

Quicksort is a fast divide and conquer algorithm, it is the fastest known sorting algorithm, and its time complexity is O(N*lgN).
The above three methods implement the basic method of quick sorting. Although quick sorting is the fastest sorting method, when the given reference value is at the end of the array, the reference value is the largest in the array. An element of , so when partitioning, it always has a left half and no right half, so when this happens, his efficiency is still relatively low (worst case), so choose the appropriate The reference value has a very important influence on the quick sorting.
Each time the left and right intervals are divided, one interval must be empty. In this case, the depth of recursion may be large. When the sorted interval is particularly large, it may cause stack overflow.
However, the probability that the selected reference value is the maximum or minimum value each time is too small, so this situation is ignored.
The above situation is an extreme analysis, but it is very possible that the selected benchmark value is close to the maximum value or close to the minimum value in the sequence, so now we give two methods for bisecting the benchmark value. : 1. Chinese method for three numbers 2. When the interval is relatively small

//在获得基准值的时候,由于会获得最大或者最小的值,因此 在基准值的选择上,将十分重要
int GetMidKey(int *array, int left,int right)
{
    assert(array || left-right<0);
    int mid = left + ((right - left) >> 1);
    if (array[left] < array[right - 1])
    {
        if (array[left] > array[mid])
            return left;
        else if (array[right - 1] < array[mid])
            return right - 1;
        else
            return mid;
    }
    else
    {
        if (array[left] < array[mid])
            return left;
        else if (array[mid] < array[right - 1])
            return right - 1;
        else
            return mid;
    }
}
//在此处给出的是开区间
//升序
int Partition1(int*array, int left, int right)
{
    //int key = right-1;
    int index = GetMidKey(array, left,right);
    if (index != (right-1))
        swap(array[index], array[right-1]);
    int key = array[right-1];
    int begin = left;
    int end = right-1;
    while (begin < end)
    {
        while (begin < end && array[begin] <= key)//此处加等于的原因是:如果碰到相等的元素,不论是拍到左边还是右边是没有影响的
        {
            ++begin;
        }
        while (begin < end && array[end] >= key)
        {
            --end;
        }
        if (begin < end)
            swap(array[begin], array[end]);
    }
    //两个指针相遇的时候,交换相遇的地方与最后一个元素,即基准值
    if (begin != right)
    {
        swap(array[begin], array[right-1]);
    }
    return begin;
}

//方式二,挖坑法
//升序
int Partition2(int*array, int left, int right)
{
    //int key = array[right];//将基准值保存
    int index = GetMidKey(array, left,right);
    if (index != (right-1))
        swap(array[index], array[right-1]);
    int key = array[right-1];
    int begin = left;
    int end = right-1;
    while (begin < end)
    {
        while (begin < end && array[begin] <= key)
            ++begin;
        //填坑
        if (begin < end)
        {
            array[end] = array[begin];
            end--;
        }

        while (begin < end && array[end] >= key)
            --end;

        if (begin < end)
        {
            array[begin] = array[end];
            begin++;
        }

    }
    //begin与end相遇,则用基准值去填充这个坑

    array[begin] = key;

    return begin;
}

//方式三,前后指针
//升序
int Partition3(int*array, int left, int right)
{
    assert(array);
    int cur = left;
    int pre = cur - 1;
    int index = GetMidKey(array, left, right);//优化
    if (index != (right-1))
    {
        swap(array[index], array[right-1]);
    }
    int key = array[right-1];
    while (cur < right)
    {
        while (array[cur] < key&&++pre != cur)
        {
            swap(array[pre], array[cur]);
        }
        ++cur;//让cur走到下一个位置,从而开始新的一轮的比较
    }
    if (++pre != right)
        swap(array[pre], array[right-2]);
    return pre;
}

//开区间
//优化---->1、在区间元素较少之时,且区间中的元素较为有序之时,则采用插入排序,从而提高程序的效率2、在获取基准值之时,尽量将基准值不给在区间的最大值或者最小值
void QuickSort(int *array, int left, int right)
{
    assert(array || left < 0 || right < 0);
    //当区间中的元素个数较少,则采用插入排序,更加能节省时间
    if (right - left < 10)
        InsertSort(array, right - left);
    else
    {
        if (left < right)
        {
            size_t div = Partition3(array, left, right);
            QuickSort(array, left, div);
            QuickSort(array+div+1, div + 1, right);
        }
    }
}
//快排的非递归算法
void QuickSortNor(int *array, int left,int right)
{
    stack<int> s;
    s.push(right);
    s.push(left);

    while (!s.empty())
    {
        left = s.top();
        s.pop();
        right = s.top();
        s.pop();

        //如果区间中的元素个数大于1,则继续分块
        if (left < right)
        {
            int div = Partition1(array, left, right);
            s.push(right);
            s.push(div + 1);
            s.push(div);
            s.push(left);
        }               
    }
}

About quick row, probably so much content! ! !
What is wrong, please correct me! ! !

Only by running continuously can you not stay in place! ! !

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324771462&siteId=291194637