冒泡法
**冒泡法的核心思想:**依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,
所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数。
所以时间复杂度为O(n2)
冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。
图片演示:
//代码演示
template<typename T>
void bubblesort(T a[],T n)//冒泡法排序
{
for (int i = n - 1; i > 0; i--)
{
for (int j = 0; j < i; j++)
{
if (a[j] > a[j + 1])
{
swap(a[j] , a[j + 1]);//swap函数可以自己定义
//本身包含在#include <algorithm>头文件中
}
}
}
} ;
插入法
原理:
1.从数组的第二个数据开始往前比较,即一开始用第二个数和他前面的一个比较,如果 符合条件(比前面的大或者小,自定义),则让他们交换位置。
2.然后再用第三个数和第二个比较,符合则交换,但是此处还得继续往前比较。
3.重复步骤二,一直到数据全都排完。
//代码演示
template<typename T>
void InsertSort(T a[], T n) {//插入法排序
for (int i = 1; i < n; i++) {
T key = a[i];
T j = i - 1;
while (j >= 0 && key < a[j]) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;//大的挪到后面后插入合适位置
}
}
选择法
选择排序法是从算法优化的角度对冒泡法的改进,
其改进的思想是:经过一轮的两两比较后,并不马上交换数的位置,而是找到本轮最小的数,
记下该数的位置(即在数组中的下标)(j),待本轮比较完毕后,通过一次交换即可将本轮
最小的数交换到位。
template<typename T>
void SelcetSort(T a[], T n) {
for (int i = 0; i < n; i++) {//选择法排序
int min = a[i];
int index = i;
for (int j = i+1; j < n; j++) {
if (a[j] < min) {
min = a[j];
index = j;
}
}
swap(a[i], a[index]);//一轮下来找出最小值放在前面
}
}
归并法
思路:假设数组有n个数,先将其分为两半,再对这两半继续对半分隔...
重复操作直到分隔后的小部分只有一个数。接着对这两个数进行归并操作,
归并后得到一个有序的两个数组成的小数组,再将其与另一个有序的两个数组成的小数组进行归并,
重复操作,直到所有数组有序。
template<typename T>//归并过程
void Merge(T a[], T l, T mid, T r) //l为第1有序区的第1个元素,i指向第1个元素, r为第1有序区的最后1个元素
{
int *t = new int[r - l + 1];//t数组暂存合并的有序序列
int q = mid + 1;
int i = 0;
int left = l;
while (left <= mid && q <= r)
{
if (a[left] <= a[q])
{
t[i] = a[left];
i++;
left++;
}
else
{
t[i] = a[q];
i++;
q++;
}
}
while (left <= mid) //若比较完之后,第一个有序区仍有剩余,则直接复制到t数组中
{
t[i] = a[left];
i++;
left++;
}
while (q <= r)
{
t[i] = a[q];
i++;
q++;
}
for (T j = 0; l <= r; j++)
{
a[l] = t[j];
l++;
}
delete []t;//释放内存,由于指向的是数组,必须用delete []
};
template<typename T>
void MergeSort(T a[], T l, T r) //归并法排序
{
T mid = l + (r-l) / 2;
if (l >= r)
{
return;// 终止递归的条件,子序列长度为1
}
MergeSort(a, l, mid); //对左半边递归
MergeSort(a, mid + 1, r); // 对右半边递归
Merge(a, l,mid, r); // 合并
}
快速排序
【思路】:每轮选择一个基准元素(比如第一个),将待排序的记录分割成两部分,
一部分的元素值均比基准元素值小,另一部分比基准值大,然后分别对这两部分用同样的方法排序。
一般基于递归实现。冒泡排序每次只调整了一个数或几个数的相对关系,而快速排序每遍都让两边保持相对关系。
template<typename T>
void QuickSort(T left, T right,T arr[]) {//快速排序
if (left >= right)
return;
int idx = rand() % (right - left + 1) + left;//加上随机数加快排序速度
swap(arr[idx], arr[left]);
int i, j, base, temp;
i = left, j = right;
base = arr[left]; //取最左边的数为基准数
while (i < j)
{
while (arr[j] >= base && i < j)//必须先j--然后再i++
j--;
while (arr[i] <= base && i < j)
i++;
if (i < j)
{
swap(arr[i], arr[j]);
}
}
//基准数归位
arr[left] = arr[i];
arr[i] = base;
QuickSort(left, i - 1, arr);//递归左边
QuickSort(i + 1, right, arr);//递归右边
}
下面是测试代码:
//
int main()
{
int n=10 ;
int a[10] = { 2,3,5,6,4,9,4,5,2,1};
QuickSort(0,9,a);
for (int m = 0; m < n; m++)
std::cout <<a[m]<<endl;
return 0;
}