/*
快速排序:是从冒泡排序算法演变而来的,实际上是在冒泡排序基础上的递归分治法。
它是通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,
则可以分别对这两部分记录继续进行排序,以达到整个序列有序。
模板如下:
*/
void quickSort(int* arr, int L, int R)
{
if (L > R) return;
int left = L, int right = R;
int pivot = arr[left];
while (left < right){
while (left < right && arr[right] >= pivot) {
right--;
}
if (left < right) {
arr[left] = arr[right];
}
while (left < right && arr[left] <= pivot) {
right--;
}
if (left < right) {
arr[right] = arr[left];
}
if (left >= right) {
arr[left] = pivot;
}
}
quickSort(arr, L, right - 1);
quickSort(arr, right + 1, R);
}
归并排序
所谓归并是指两个或两个以上的有序表合并成一个新的有序表。
- 思路:
1、将n个记录的待排序序列看成是有n个长度都为1的有序子表组成。
2、将两两相邻的子表归并为一个有序子表。
3、重复上述步骤,直至归并为一个长度为n的有序表。2.归并排序过程示例
代码实现:
#include <bits/stdc++.h >
using namespace std;
void merge(int* a, int low, int mid, int hight) //合并函数
{
int* b = new int[hight - low + 1]; //用 new 申请一个辅助函数
int i = low, j = mid + 1, k = 0; // k为 b 数组的小标
while (i <= mid && j <= hight)
{
if (a[i] <= a[j])
{
b[k++] = a[i++]; //按从小到大存放在 b 数组里面
}
else
{
b[k++] = a[j++];
}
}
while (i <= mid) // j 序列结束,将剩余的 i 序列补充在 b 数组中
{
b[k++] = a[i++];
}
while (j <= hight)// i 序列结束,将剩余的 j 序列补充在 b 数组中
{
b[k++] = a[j++];
}
k = 0; //从小标为 0 开始传送
for (int i = low; i <= hight; i++) //将 b 数组的值传递给数组 a
{
a[i] = b[k++];
}
delete[]b; // 辅助数组用完后,将其的空间进行释放(销毁)
}
void mergesort(int* a, int low, int hight) //归并排序
{
if (low < hight)
{
int mid = (low + hight) / 2;
mergesort(a, low, mid); //对 a[low,mid]进行排序
mergesort(a, mid + 1, hight); //对 a[mid+1,hight]进行排序
merge(a, low, mid, hight); //进行合并操作
}
}
int main()
{
int n, a[100];
cout << "请输入数列中的元素个数 n 为:" << endl;
cin >> n;
cout << "请依次输入数列中的元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
mergesort(a, 0, n-1);
cout << "归并排序结果" << endl;
for (int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
效率分析:
对n个元素的序列,执行二路归并算法,则必须做 log2n趟归并,每一趟归并的时间复杂度是O(n),所以二路归并的时间复杂度为O(
l
o
g
2
n
log_2n
log2n)
两路归并排序需要和待排序序列一样多的辅助空间。其空间复杂度为O(n)。
两路归并排序也是一种稳定性的排序。
二分查找
也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
基本思路:
在有序表中,取中间元素作为比较对象,若给定值与中间元素的关键字相等,则查找成功;若给定值小于中间元素的关键字,则在中间元素的左半区继续查找;若给定值大于中间元素的关键字,则在中间元素的右半区继续查找。不断重复上述查找过程,直到查找成功,或所查找的区域无数据元素,查找失败。
主要步骤:
1、置初始查找范围:low=1,high=n(设置初始区间)
2、求查找范围中间项:mid=(low+high)/2(取中间点位置)
3、将指定的关键字值k与中间项的关键字比较:
- 若相等,查找成功,找到的数据元素为此时mid指向的位置;
- 若k小于中间项关键字,查找范围的低端数据元素指针low不变,高端数据元素指针high 更新为mid-1;
4、重复步骤2、3直到查我成功或查找范围为空(low>high),即查找失败为止。
5、如果查找成功,返回找到元素的存放位置,即当前的中间项位置指针mid;否则返回查找失败标志。
代码实现:
#include<iostream>
using namespace std;
int a[100];
int binary_scarch(int a[],int len,int e){
int left=0;
int right=len;
int mid;
while(left<=right){
int mid=(left+right)/2;
if(a[mid]>e){
right=mid-1;
}else if(a[mid]<e){
left=mid+1;
}else{
return mid;
}
}
return -1;
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int e;
cin>>e;
cout<<binary_scarch(a,n-1,e);
}
二分查找它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。
优点:比较次数少,查找速度快,平均性能好 ,占用系统内存较少
缺点:待查表为有序表,插入删除困难
- 二分查 找依赖的是顺序表结构,也就是数组,需要能够按照下标随机访问元素
- 二分查找针对的是有序数据,如果数据无序,需要先进行排序。而如果有频繁的插入、删除操作,则每次查找前都需要再次排序,这时候,二分查找将不再适用。
- 数据量太大或是太小都不适合用二分查找。