编译器版本: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;
}
}
}