七大排序算法(C++)
1.快速排序
1、首先设定一个分界值,通过该分界值将数组分成左右两部分。
2、将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
代码实现
int part(vector<int> &arr, int left, int right)//找到基准元素的位置(循环一次基准元素的位置就是他最终的位置)
{
int keyi = left;
while (left < right) //这里的left < right是判断下一次循环是否进行
{ //这里的left < right是限制不能找过界
while (left < right&&arr[keyi] <= arr[right])//右边找小
{
right--;
}
while (left < right && arr[keyi] >= arr[left])//左边找大
{
left++;
}
swap(arr[right], arr[left]);
}
swap(arr[left], arr[keyi]);
return left;
}
void Quicksort(vector<int> &arr,int begin,int end)
{
if (begin >= end)//该区间只有一个数了或者该区间不存在
{
return;
}
int pivotPos = part(arr, begin, end);
Quicksort(arr, begin, pivotPos - 1);//递归左区间
Quicksort(arr, pivotPos + 1, end);//递归右区间
}
2.插入排序
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤 2~5
代码实现
void insterSort(vector<int> &arr,int n)
{
//把[0,end]当成是有序的 插入tmp依旧有序
for (int i = 1; i < n; i++)
{
int end = i-1;
int tmp = arr[i];
while (end >= 0)
{
if (arr[end] > tmp)//如果要插入的数比前面有序数组最大数的小
{
arr[end + 1]=arr[end]; //把有序数组最后一位往后挪一位(就是tmp原来的位置)
--end;
}
else
{
break;
}
}
arr[end+1] = tmp;
}
}
3.希尔排序
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
代码实现
void shellSort(vector<int>& arr,int n) //希尔排序
{
// 定义间隔序列,通常选择的间隔序列为 h = n / 2, h = h / 2, ...
for (int gap = n / 2; gap > 0; gap /= 2)
{
// 对每个子序列进行插入排序
for (int i = gap; i < n; i++)
{
int temp = arr[i];
int j;
// 在子序列中执行插入排序
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
{
arr[j] = arr[j - gap];
}
arr[j] = temp;
}
}
}
4.冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码实现
void bubbleSort(vector<int> &arr, int n)
{
bool swapped;
for (int i = 0; i < n - 1; i++)
{
swapped = false;
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
swapped = true;
}
}
if (!swapped)
{
break;
}
}
}
5.选择排序
它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
代码实现
void SelectSort(vector<int> &arr, int n)//选择排序
{
for (int i = 0; i < n - 1; i++)
{
int minIndex = i;
for (int j = i + 1; j < n ; j++)
{
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
swap(arr[minIndex],arr[i]);
}
}
6.堆排序
在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:
1.最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
2.创建最大堆(Build Max Heap):将堆中的所有数据重新排序
3.堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
代码实现
void AdJustUp(vector<int> &arr, int child)//建堆——向上调整
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] > arr[parent])
{
swap(arr[child], arr[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void AdJustDown(vector<int> &arr,int n,int parent)
{
int child = parent * 2 + 1;//左孩子
while (child < n )//当后面没有孩子的时候就返回
{
if (child+1<n&&arr[child]<arr[child+1])//找出左右孩子中小/大的一个(右孩子存在并且比左孩子大/小)
{
child++;
}
if (arr[child] > arr[parent])
{
swap(arr[child], arr[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(vector<int> &arr, int n)//堆排序
{
//建堆——向上调整(小堆)
for (int i = 1; i < n ; i++)
{
AdJustUp(arr, i);
}
int end=n-1;
while (end > 0)
{
swap(arr[0], arr[end]);
//再调整选出次小的数
AdJustDown(arr,end,0);
end--;
}
}
7.归并排序
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
代码实现
void Merge(vector<int> &arr,vector<int> &arr1,int begin,int mid,int end)
{
int i = begin, j = mid + 1, k = end;
//i、j 分别标记第一和第二个数列的当前位置,k 是标记当前要放到整体的哪一个位置
while (i <= mid && j <= end) //如果两个数列的数都没放完,循环
{
if (arr[i] < arr[j])
arr1[k++] = arr1[i++];
else
arr1[k++] = arr[j++]; //将a[i] 和 a[j] 中小的那个放入 b[k],然后将相应的标记变量增加
} // b[k++]=a[i++] 和 b[k++]=a[j++] 是先赋值,再增加
while (i <= mid)
arr1[k++] = arr[i++];
while (j <= end)
arr1[k++] = arr[j++]; //当有一个数列放完了,就将另一个数列剩下的数按顺序放好
for (int i = begin; i <= end; i++)
arr[i] = arr1[i]; //将 b 数组里的东西放入 a 数组,因为 b 数组还可能要继续使用
}
void MergeSort(vector<int>& arr, int begin, int end)//归并排序
{
vector<int> arr1;
if (begin >= end)//如果开头 ≥ 结尾,那么就说明数列分完了,就要返回
{
return;
}
int mid = (begin + end) / 2; //将中间数求出来,用中间数把数列分成两段
MergeSort(arr,begin, mid);//左区间
MergeSort(arr,mid + 1, end);//右区间 //递归,继续分离
Merge(arr,arr1,begin, mid, end); //分离玩之后就合并
}