关于排序

来源:互联网 发布:数据有效性设置 编辑:程序博客网 时间:2024/06/18 06:40

编译器版本:vs2013

排序的目的

::如果输入一系列数字a1,a2,a3,a4,a5,a6,a7
经过排序有
::输出a1< a2< a3< a4< a5< a6< a7或者
::输出a1>a2>a3>a4>a5>a6 >a7
即让一系列无序数字从大到小或者从小到大有序即为排序。

学习中的几种排序算法

1:插入排序
基本思想:
升序:给一个数组,并不知道是否有序,从第二个数开始依次往后直到数组最后一个元素,挨个和前面那个数比大小,大的放这个数后面,小的接着和前面数比,如果比前面每一个数都小,就放在最前面,依次循环比完每一个数。
降序和升序思想一致,只是要把大的放在前面,小的放在后面。

具体代码

void Insertsort(int* a, size_t n){    assert(a);    for (size_t i = 0; i<n - 1; ++i)    {        int end = i;        int tmp = a[end + 1];        while (end >= 0)        {            if (a[end] > tmp)            {                a[end + 1] = a[end];                --end;            }            else            {                break;            }        }        a[end + 1] = tmp;    }}

给一个整型数组a,数组元素n个,首先assert数组不能为空,空数组不需要排序,
这里写图片描述
i是下标,从0开始,上图中每一个b都是在所画圆圈区域内即将要插入得数,思想在上面已经讲过,就是每一个即将要插入的数和前面的数相比,比前面一个数大就差到那个数后面,找不到要插入的位置就需要一直找,找完已经排序完成的所有数为止,当然,既然是插入,在插入一个新的数以后,排在这个数后面的那些书当然要往后挪一下位置了。

2:希尔排序
希尔排序就是升级版的插入排序,在中间加了一个间距gap,只是为了更快的将前面的大数据和后面的小数据换回来,达到的效果是预排序,
这里写图片描述
假如gap=3,那么就是在这个数组中隔三个数做排序,这样可以尽快把后面的小数据和前面的大数据交换,思想和前面的插入排序一样

void shellsort(int* a, size_t n){    assert(a);    int gap = 3;    for (size_t i = 0; i < n - gap; ++i)    {        int end = i;        int tmp = a[end + gap];        while (end >= 0)        {            if (a[end] > tmp)            {                a[end + gap] = a[end];                end -= gap;            }            else            {                break;            }        }        a[end + gap] = tmp;    }}
 end=i; tmp=a[end+gap]; 要插入的新元素是tmp,tmp先和前面的a[end]比较,若a[end]大,将a[end]往后挪,end-=gap;再比,知道不满足while或者if条件,a[end + gap] = tmp;完成插入;

3:选择排序
具体思想:升序–给一个无序数组,min和max分别表示数组中最小和最大数的下标,两个都是从0下标开始,找到两个数以后,最小值换到0下标位置,最大值换到n-1下标位置,

void Selectsort(int* a, size_t n)//选下标{    assert(a);    size_t left = 0;     size_t right = n - 1;    while (left < right)    {        size_t min = left, max = left;        for (size_t i = left; i < right; ++i)        {            if (a[i]< a[min])            {                min = i;            }            if (a[i] > a[max])            {                max = i;            }            swap(a[min], a[left]);            //9 0 1 2 4 5 7            //下面这个if条件判断的就是类似上面这类情况,此时min是            //数组元素0的下标,left是9的下标同时也是数组最大元素9            //的下标,把0和9交换以后,9的下标即刚才交换之前0的下标            //而把最小值换到最左边以后需要做的就是把最大值换到最右边            //最大值现在是9,即a[min],所以需要把max赋值为min和最            //右边交换,然后--left,--right,在剩下的数里面找最大最            //小接着上面的操作            if (max == left)            {                max = min;            }            swap(a[max], a[right]);            ++left;            --right;        }    }}

4:快速排序
具体思想:就是把数组通过多次划分成小区间,甚至这个小区间里面就一个数,把小区间划分排序成有序区间再组合起来就是一个大的有序数组。

int Partsort1(int *a, int left, int right)   //挖坑{    int key = a[right];    int begin = left;    int end = right;    while (begin < end)    {        while (a[begin] <= key)        {            ++begin;        }        if (begin < end)        {            swap(a[end], a[begin]);        }        while (a[end] >= key)        {            --end;        }        if (begin < end)        {            swap(a[begin], a[end]);        }    }    swap(a[begin], a[right]);    return begin;}int Partsort2(int *a,int left,int right)   //左右指针{    int key = a[right];    while (left < right)    {        while (left < right&&a[left] <= key)        {            ++left;        }        a[right] = a[left];        while (left < right&&a[left] >= key)        {            --right;        }        a[left] = a[right];    }    a[left] = key;}int Partsort3(int *a, int left, int right)   //前后指针{    int cur = left;    int key = a[right];    int prev = left - 1;    while (cur < right)    {        if (a[cur] < a[key] && ++prev != cur)        {            swap(a[prev], a[cur]);        }        ++cur;    }    swap(a[++prev], a[right]);    return prev;}void Quicksort(int *a, int left, int right){    assert(a);    if (left >= right)    {        return;    }    else    {        int div = Partsort1(a, left, right);        int div = Partsort2(a, left, right);        int div = Partsort3(a, left, right);        Quicksort(a, left, div - 1);        Quicksort(a, div + 1, right);    }}

5:快排非递归实现
具体思想:利用stack先入后出,实现数组划分成小区间,小区间依次排序实现有序并合并以后实现大数组有序。

int Partsort1(int *a, int left, int right)   //挖坑{    int key = a[right];    int begin = left;    int end = right;    while (begin < end)    {        while (a[begin] <= key)        {            ++begin;        }        if (begin < end)        {            swap(a[end], a[begin]);        }        while (a[end] >= key)        {            --end;        }        if (begin < end)        {            swap(a[begin], a[end]);        }    }    swap(a[begin], a[right]);    return begin;}int Partsort2(int *a,int left,int right)   //左右指针{    int key = a[right];    while (left < right)    {        while (left < right&&a[left] <= key)        {            ++left;        }        a[right] = a[left];        while (left < right&&a[left] >= key)        {            --right;        }        a[left] = a[right];    }    a[left] = key;}int Partsort3(int *a, int left, int right)   //前后指针{    int cur = left;    int key = a[right];    int prev = left - 1;    while (cur < right)    {        if (a[cur] < a[key] && ++prev != cur)        {            swap(a[prev], a[cur]);        }        ++cur;    }    swap(a[++prev], a[right]);    return prev;}void Quicksort(int *a, int left, int right){    assert(a);    if (left >= right)    {        return;    }    else    {        int div = Partsort1(a, left, right);        int div = Partsort2(a, left, right);        int div = Partsort3(a, left, right);        Quicksort(a, left, div - 1);        Quicksort(a, div + 1, right);    }}void Quicksort(int *a, int left, int right){    stack<int> s;    if (left < right)    {        s.push(right);        s.push(right);        while (s.empty())        {            int begin = s.top();            s.pop();            int end = s.top();            s.pop();            int div = part1(a, begin, end);            int div = part2(a, begin, end);            int div = part3(a, begin, end);            if (begin < div - 1)            {                s.push(div - 1);                s.push(begin);            }            if (div + 1 < end)            {                s.push(end);                s.push(div + 1);            }        }    }}

6:归并排序
基本思想:归并排序有点类似于合并两个有序链表
归并排序是建立在归并操作上的一种有效的排序算法,该算法和快速排序都是采用分治法来设计算法的,区别在于归并排序把数组分为两个基本等长(最多相差一个元素)的子数组,分别排好序之后还要进行归并操作,而快速排序在拆分子数组的时候则有所不同,其取一个基准元素,拆分之后基准元素左边的元素都比基准元素小,右边的元素都不小于基准元素,这样只需要分别对两个子数组排序即可,不再像归并排序一样需要归并操作。归并排序是稳定的算法,其最坏的时间复杂度是O(n^2),其最好的时间复杂度是O(nlogn).
假设有数组 a,比较 a[i] 和 a[j] 的大小,若 a[i] ≤ a[j],则将第一个有序表中的元素 a[i] 复制到 r[k] 中,并令 i 和 k 分别加上 1;否则将第二个有序表中的元素 a[j] 复制到 r[k] 中,并令 j 和 k 分别加上 1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到 r 中从下标 k 到下标 t 的单元。归并排序的算法我们通常用递归实现,先把待排序区间 [s,t] 以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间 [s,t].

void _Merge(int *a, int* tmp, int begin1, int end1, int begin2, int end2){    size_t index = begin1; size_t pos = begin2;    while (begin1 < end1&&begin2 < end2)    {        if (a[begin1] < a[begin2])        {            tmp[index++] = a[begin1++];        }        else        {            tmp[pos++] = a[begin2++];        }    }    if (begin1 >= end1)    {        while (begin2 < end2)        {            tmp[pos++] = a[begin2++];        }    }    else if (begin2 >= end2)    {        while (begin1<end1)        {            tmp[index++] = a[begin1++];        }    }    else    {        return;    }    memcpy(a + pos, tmp + pos, sizeof(int)*(end2 - pos + 1));}void _Mergesort(int*a, int *tmp, int left, int right){    if (left >= right)    {        return;    }    else    {        int mid = left + (left + right) / 2;        _Mergesort(a, tmp, left, mid);        _Mergesort(a, tmp, mid + 1, right);        _Merge(a, tmp, left, mid, mid + 1, right);    }}void Mergesort(int *a, size_t n){    assert(a);    int *tmp = new int[n];    _Mergesort(a, tmp, 0, n - 1);}

7:冒泡排序
基本思想:即对相邻两个数进行比较,如果反序就交换位置,直到整个序列没有出现反序为止。
代码里面的flag是优化部分,如果第一趟没有发现有交换产生,则直接跳出循环,

void Bubble_sort(int *a, size_t n){    int i, j, temp;    bool flag = true;    for (i = n - 1; i >= 0; i--)    {        flag = false;        for (j = 0; j < i; j++)        {            if (a[j] >a[j + 1])            {                temp = a[j + 1];                a[j + 1] = a[j];                a[j] = temp;                flag = true;            }            if (flag == false) break;        }    }}