数据结构-排序
直接插入
![image-20231221233828975](https://i-blog.csdnimg.cn/blog_migrate/da1be068cad8aeee1ee8871cc0d495ec.png)
折半插入
希尔排序
#include <iostream>
using namespace std;
// 希尔排序函数
void ShellSort(int *arr, int len) {
int grp = len / 2; // 计算增量
for (; grp > 0; grp = grp / 2) { // 每次计算完一轮,增量再除以二
// 选择排序
for (int i = grp; i < len; i++) {
int cur = arr[i]; // 先空出第二个数的位置
int j = 0;
// 根据增量往前比较,小的在前,大的在后
for (j = i - grp; j >= 0 && arr[j] > cur; j = j - grp) {
arr[j + grp] = arr[j]; // 符合条件将前面的数据移动到空出的位置
}
arr[j + grp] = cur; // 最后将待插入数据cur插入到前面空出的位置
}
}
}
起泡排序(加强)
在每一次起泡的过程中加入一次标志,查看有没有交换,如果没有交换就表示全部正确
快速排序
// 分区函数
//遍历一遍,然后把小于的按顺序存放;最后把我的中间元素放在下一位
int partition(int* arr, int low, int high, int pivot) {
// 将枢轴元素放在数组的中间
int pivotIndex = (low + high) / 2;
swap(arr[pivotIndex], arr[high]);
// 将数组分为两部分,一部分比枢轴小,另一部分比枢轴大
int partitionIndex = low;
for (int i = low; i < high; i++) {
if (arr[i] < pivot) {
swap(arr[i], arr[partitionIndex]);
partitionIndex++;
}
}
// 将枢轴元素放在正确的位置
swap(arr[partitionIndex], arr[high]);
// 返回枢轴元素的索引
return partitionIndex;
}
// 快速排序算法
void quickSort(int* arr, int low, int high) {
// 递归基线条件
if (low >= high) {
return;
}
// 选择一个枢轴元素
int pivot = arr[high];
// 将数组分为两部分,一部分比枢轴小,另一部分比枢轴大
int partitionIndex = partition(arr, low, high, pivot);
// 对两部分递归调用快速排序
quickSort(arr, low, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, high);
}
// 交换两个元素
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
选择排序
最大堆
归并排序
- 一个排列中所有逆序总数叫做这个排列的逆序数。
- 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。
作业
当一个比较大的元素位于更大的元素右侧,且二者在偏离自己位置的时候;这个元素就会朝相反方向移动
比如 9 8 1 2->8 9 1 2->8 1 9 2->8 1 2 9,在这轮起泡中,8被向左移动了,相对于其位置[2],是相反的
在快速排序中,由于进行分块,比选定元素小的会被进行按顺序插入新的序列之中,不会进行两两元素分别比较,因此一般不会,但是局部也会出现这种情况
1 2 3 7 5 4 6,选定6作为枢纽
1 2 3 5 4 6 7此时5本来在自己应该的位置,但是被左移了一次
和交换对于B之后的元素没有影响,对于A之前的元素没有影响,仅仅对于介于AB之间的元素来说,减少的逆序 = 比A小的元素个数 + 比B大的元素个数 - 比A大的元素个数 - 比B小的元素的元素个数 + AB本身是否是一对逆序所导致的变化
考虑极限情况,AB在首尾,并且AB分别为最大和最小,减少的逆序为 2 ∗ ( n − 2 ) + 1 2*(n-2)+1 2∗(n−2)+1
即 2 n − 3 2n-3 2n−3
使用栈进行非递归快速排序的简要过程:
-
将整个数组的初始范围(通常是整个数组)入栈,表示待排序区间。
-
循环执行以下步骤,直到栈为空:
a. 弹出栈顶的待排序区间,记为[left, right]。
b. 对该区间进行快速排序的一次划分,得到枢纽元素的位置pivot。
c. 如果划分后的左右子数组非空,则将左右子数组的范围分别入栈。
从中我们不难看出,每一次的结果对于别的区域没有什么影响,也就是先入先出或者先入后出没有什么区别
-
将整个数组的初始范围(通常是整个数组)入队,表示待排序区间。
-
循环执行以下步骤,直到栈为空:
a.将栈顶的待排序区间出队,记为[left, right]。
b. 对该区间进行快速排序的一次划分,得到枢纽元素的位置pivot。
c. 如果划分后的左右子数组非空,则将左右子数组的范围分别入队。
void cocktailSort(std::vector<int> &arr){
int high = 0;
bool switched = false;
for(int i = 0;i < arr.size();i++){
high = 0;
switch(i %2){
case(0):
//偶数代表从左到右
for(int j = i/2;j < arr.size() -1;j++){
if(arr[j] > arr[j+1]){
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
high = j+1;
}
}
break;
case(1):
//基数代表从右到左
for(int j = arr.size()-1 - i/2;j > 0;j--){
if(arr[j] < arr[j-1]){
int temp = arr[j];
arr[j] = arr[j-1];
arr[j -1] = temp;
high = j;
}
}
break;
}
//没有交换表示成功
if(0 == high){
break;
}
}
}
![image-20231222224247355](https://i-blog.csdnimg.cn/blog_migrate/8f4e3946f0101a02375b3c61540364e1.png)
(1) 结束的条件是当一趟奇数扫描和一趟偶数扫描都没有发生交换时,表明序列已经排好序,排序过程结束。
(2) 奇偶交换排序的算法如下:
void oddEvenSort(int arr[], int n) {
bool sorted = false;
while (!sorted) {
sorted = true;
// 奇数项扫描
for (int i = 1; i < n - 1; i += 2) {
if (arr[i] > arr[i + 1]) {
swap(arr[i], arr[i + 1]);
sorted = false;
}
}
// 偶数项扫描
for (int i = 0; i < n - 1; i += 2) {
if (arr[i] > arr[i + 1]) {
swap(arr[i], arr[i + 1]);
sorted = false;
}
}
}
}
(3) 当待排序序列的初始排列是从小到大有序时,奇偶排序过程中的排序码比较次数是n-1
这是因为在每一趟奇数扫描和偶数扫描中,每一对相邻的元素都需要比较和可能的交换。在最坏情况下,每一对元素都需要交换,导致总的比较次数为O( ( n − 1 ) 2 (n-1)^2 (n−1)2)。
// 交换数组中两个元素的位置
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
// 分割函数,选取一个枢纽元素将数组分成两部分
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int pos = low;
for(int i = low;i < high;i++){
if(arr[i] <= pivot){
swap(arr[i],arr[pos]);
pos++;
}
}
swap(arr[high],arr[pos]);
return pos;
}
void quickSort(int a[],int low,int high){
queue<pair<int,int>> q;
q.push({low,high});
while(!q.empty()){
pair<int,int> current = q.front();
q.pop();
int low_1 = current.first;
int high_1 = current.second;
if(low_1 < high_1){
int pivot = partition(a,low_1,high_1);
q.push({low_1,pivot -1});
q.push({pivot+1,high_1});
}
}
}
![image-20231222232817675](https://i-blog.csdnimg.cn/blog_migrate/c4251f968c690c0e6b52ff2b68a538e2.png)