重点记忆:插入排序 堆排序 归并排序 快速排序
稳定排序:相同元素的前后顺序并没有改变
不稳定的排序算法有:快、希、选、堆。
https://baijiahao.baidu.com/s?id=1602011058247698952&wfr=spider&for=pc
插入排序:样本小且基本有序的时候效率比较高 优于冒泡和选择
希尔排序:插入排序升级 间隔大时移动的次数少 间隔小时移动的距离短 (不稳定 )
口诀:
选泡插,
快归堆希统计基,
恩方恩老恩一三,
对恩加k/恩乘K,
不稳稳稳不稳稳,
不稳不稳稳稳稳!
代码详细说明看注释
排序算法检验函数
下面的算法使用该函数验证
void Random(int* a, int n, int l, int r)//生成范围在l~r的随机数
{
srand(time(0)); //设置时间种子 取系统时间
for (int i = 0; i < n; i++) {
a[i] = rand() % (r - l + 1) + l;//生成区间r~l的随机数
}
}
void check()
{
int n = 1000;
int* arr1= new int[n];
Random(arr1, n, 0, 1000);
vector<int> check_num(arr1, arr1 + n);
sort(check_num.begin(), check_num.end());
;
quick_sort(arr1, 0, n - 1);//检验快排算法
bool same = true;
for (int i = 0; i < n; i++)
{
if (arr1[i] != check_num[i]) same = false;
}
same == true ? cout << "right" << endl : cout << "false" << endl;
}
1.快速排序
核心思想:
参考链接
https://developer.51cto.com/art/201403/430986.htm
/*1.先从数列中取出一个数作为基准数。
1.1 直接取第一个元素
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
2.1 两个指针i,j分别指向头尾,相向而行。先移动j,直到j找到一个小于等于基准数的,i找到一个大于基准数的,交换他们。
2.2 继续2.2 直到i=j ,交换这个位置和首元素
3.再对左右区间重复第二步,直到各区间只有一个数
3.1 递归
//手写快排
int quick_sort_partition(int nums[],int left,int right)
{
int axis = left;
int i = left+1;
int j = right;
int n = right-left + 1;
//printf_array(nums, n);
while (i <=j)//比轴小得都放到轴得左边,比轴大的都放在右边
{
while (i<=j && nums[i] <= nums[axis]) i++;
while (i<=j && nums[j] > nums[axis]) j--;
if (i < j)
{
swap(nums[i], nums[j]);
}
//printf_array(nums, n);
//cout << "----" << endl;
}
swap(nums[i-1], nums[left]);
//printf_array(nums,n);
return i - 1;
}
void quick_sort(int nums[], int left, int right)
{
if (left >= right) return;
int mid = quick_sort_partition(nums, left, right);
quick_sort(nums, left, mid - 1);
quick_sort(nums, mid + 1, right);
}
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
int n = sizeof(nums2) / sizeof(nums2[0]);
quick_sort(nums2, 0, n-1);
return 0;
}
2.归并排序
递归注意结束条件、递归公式
先递归,再合并
1.完成数组拆分,直到拆成单个元素
2.完成两个分别有序子序列合并得功能函数
int printf_array(int nums[],int n)
{
for (int i = 0; i < n; i++)
{
cout << nums[i] << endl;
}
return 0;
}
//合并函数
//1.先解决子问题 两个有序数组如何合并成一个新的有序数组
//2.再修改边界条件 这里将left mid right_bound 均为数组下标 左闭右闭写法
//3.再写拆得过程 也就是递归得过程
void merge(int nums[], int left,int mid,int right_bound)
{
int i = left;
int j = mid+1;
int* temp = new int[right_bound-left+1];
int k = 0;
while (i <= mid && j <= right_bound)
{
temp[k++] = nums[i] >= nums[j] ? nums[j++] : nums[i++];
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right_bound) temp[k++] = nums[j++];
for (int i = 0; i < right_bound - left + 1; i++)
{
nums[left + i] = temp[i];
}
//printf_array(temp, right_bound - left + 1);
}
//拆分
//这里要注意边界条件一定要统一,这里全部采用左闭右闭得区间
void merge_sort(int nums[], int left, int right)
{
if (left < right)//边界条件
{
int mid = (left + right) / 2;
merge_sort(nums,left,mid);
merge_sort(nums,mid+1,right);
merge(nums, left, mid, right);
}
/*int num[] = { 1,3,4,2,5,6 };
merge(num, 1,2,4);*/
}
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
int nums2[] = { 6,1,2,7,9,3,4,5,10,8,2 };
int n = sizeof(nums2) / sizeof(nums2[0]);
//selection_sort(nums);
//insertion_sort(nums, nums.size());
//shell_sort(nums, nums.size());
//shell_sort2(nums, nums.size());
//bubble_sort(nums, nums.size());
merge_sort(nums2, 0,n-1);
printf_array(nums2,n);
//cout << nums.size() << endl;
//system("pause");
return 0;
}
3.插入排序
/插入排序
//***********************************
//一个指针遍历未排序的序列,待比较数字过来后,从后往前遍历,若比较数字小于该数字,则交换这两个数字,一直到大于或到数组头
//外层循环遍历未排序的序列并插入
int insertion_sort(vector<int>& nums, int n)
{
for (int i = 0; i < n; i++)
{
for (int j = i ; j > 0 && nums[j-1]>nums[j]; j--)
{
swap(nums[j], nums[j - 1]);
}
}
return 0;
}
//****************************************
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
insertion_sort(nums, nums.size());
printf_array(nums);
return 0;
}
4.希尔排序
//希尔排序
//插排的升级 数组后面比较小的元素会移动更少的次数到前面
//将数组按照gap间隔分成若干组,对每组分别进行插入排序,然后缩小间隔再进行排序,直到间隔为1,最后进行一次插入排序
void shell_sort(vector<int> & nums,int n)
{
for (int gap = nums.size(); gap > 0; gap /= 2)
{
for (int i = gap; i < n; i++)//是几组同步进行
{
for (int j = i; j >gap-1 && nums[j] < nums[j - gap]; j -= gap) //新元素与有序序列的元素比较
{
swap(nums[j], nums[j - gap]);
}
}
}
}
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
//selection_sort(nums);
//insertion_sort(nums, nums.size());
shell_sort(nums, nums.size());
//bubble_sort(nums, nums.size());
printf_array(nums);
return 0;
}
5.冒泡排序
//****************************************
//冒泡排序
/*
1.原理:比较两个相邻的元素,将值大的元素交换到右边
2.思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
(1)第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。
(2)比较第2和第3个数,将小数 放在前面,大数放在后面。
......
(3)如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成
(4)在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。
(5)在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。
(6)依次类推,每一趟比较次数减少依次
内层遍历完一趟后,最后一个数就是最大的了,所以下一次只需要遍历到n-i+1,外层循环相当于就是记个数
*/
//****************************************
void bubble_sort(vector<int> &nums,int n)
{
bool swaped;//如果发现没有需要交换的 提前结束
for (int i = 0; i <n ; i++)
{
swaped = false;
for (int j = 1; j < n - i ; j++)
{
if (nums[j] < nums[j - 1])
{
swap(nums[j], nums[j - 1]);
swaped = true;
}
}
}
}
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
//insertion_sort(nums, nums.size());
bubble_sort(nums, nums.size());
printf_array(nums);
return 0;
}
5.选择排序
//选择排序
//*****************************************
/*
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
*/
//*****************************************
void selection_sort(vector<int>& nums)
{
int n = nums.size();
for (int i = 0; i < n; i++)
{
int j = i;
int min= nums[j];
int min_index = 0;
int flag=false;
for (; j < n; j++)
{
if (nums[j] < min)
{
min = nums[j];
min_index = j;
flag = true;
}
}
if(flag)
{
swap(nums[min_index], nums[i]);
}
}
}
int main()
{
vector<int> nums{ 6,1,2,7,9,3,4,5,10,8,2 };
selection_sort(nums);
//insertion_sort(nums, nums.size());
//bubble_sort(nums, nums.size());
printf_array(nums);
return 0;
}