目录
1.冒泡排序
1.1.算法思想
从后往前两两比较相邻元素的值,若为逆序,则交换,直到序列比较完
1.由于总是将相邻两个元素中较小的放在最前面
2.因此进行一趟冒泡以后,最左边的元素一定是最小的
3.采取递归的思想,第一轮对0-7的元素冒泡,结束后0处是最小元素
4.第二轮对1-7的元素冒泡,本轮结束后1是剩下元素中最小的
5.第三轮对2-7冒泡,这样2处的是整个列表第三小的元素
6.如此递归下去,直到对长度为1的子序列递归,这时触发递归终止条件,排序结束
(或若某次排序过程中没有发生交换,则说明数组中的元素已经整体有序,排序结束)
1.2.代码
//交换
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
//冒泡排序
void BubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
//标记此轮循环中是否进行了交换
bool flag = false;
//每次从数组中最后一个元素向前遍历,直到第i个元素
for (int j = n - 1; j >= i; j--) {
//将相邻两个逆序元素交换为正序,并更改flag
if (arr[j - 1] > arr[j]) {
swap(arr[j - 1], arr[j]);
flag = true;
}
}//for
//此次循环元素都是正序,则结束函数
if (!flag) return;
}//for
}
1.3.时间复杂度和稳定性
1.空间复杂度:O(1)
2.时间复杂度:
①最好情况:有序,比较次数n - 1,交换次数0,因此,O(n)
②最坏情况:逆序,比较次数 = 交换次数 = (n-1) + (n - 2) + ... + 1 ,O(n^2)
3.稳定性:只有当前元素的前一个元素更大的时候才交换,相等不交换,因此,该算法稳定
if (arr[j - 1] > arr[j]) swap(arr[j - 1], arr[j]);
4.适用:链表和顺序表
2.快速排序
2.1.算法思想
1.取当前表中的第一个元素(也可以是任取)为基准元素,找到它在表中的位置,即左边元素都小于它,右边元素都大于等于它,这样基准元素就确定了它在数组中的最终位置
2.以它为分割,依次到它的左表和右表进行1操作
3.重复12,直到每个表都只有一个元素为止,则整个表都有序
2.2.代码
low指针的左边都小于基准元素,high指针的右边都大于等于基准元素
1.选取49为基准元素→low当前元素为空→high指向元素49 ≥ 基准元素49,不需要移动,high--
2.high当前指向元素27 < 49→27交换到low指针指向的位置,high空
3.low当前指向元素27 < 49→low++
4.low当前指向元素38 < 49→low++
5.low当前指向元素65 > 49→65交换到high指针指向的位置,low空
6.high指向的元素65 > 49→high--
7.high指向元素13 < 49→13交换到low指针指向的位置,high空
8.low指向元素13 < 49→low++
9.low指向元素97 > 49→97交换到high指针指向的位置,low空
10.high指向元素97 > 49→high--
11.high指向元素76 > 49→high--
12.high和low指向同一元素,49插入此元素
13.对左子表划分,取27为基准元素
14.high指向元素13 > 27→13交换到low指针指向的位置,high空
15.low指向元素为13 < 27→low++
16.low指向元素为38 > 27→27交换到high指针指向的位置,low空
17.high指向元素为38 > 27→high--
18.high和low指向同一元素,27插入此元素
19.27的左右子表都为1,则不需要继续排序;对49的右子表排序,取76为基准元素
20. high指向的元素为49 < 76→49交换到low指针指向的位置,high空
21.low指向的元素为49 < 76→low++
22.low指向的元素为97 > 76,97交换到high指针指向的位置,low空
23.high指向的元素为97 > 76,high--
24.high指向的元素为65 < 76,65交换到low指针指向的位置,high空
25.low指向的元素为65 < 76,low++
26.low,high指向同一元素,将76插入此元素
27.76的左子表长度为2,去左子表继续排序,取49为基准元素
28.high指向元素65 > 49,high--
29.high,low指向同一元素,将49插入此元素
int Partition(int arr[], int low, int high){
//选取第一个元素作为基准元素
int pivot = A[low];
//循环直到low = high
while (low < high){
//当前元素比基准元素小时,将此元素移动到low指向的位置
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
//当前元素比基准元素大时,将此元素移动到high指向的位置
while (low < high && arr[low] < pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
//快速排序
void QuickSort(int arr[], int low, int high){
if (low < high){
//划分左右子表
int pivotPos = Partition(arr, low, high);
//左子表排序
QuickSort(arr, low, pivotPos - 1);
//右子表排序
QuickSort(arr, pivoPos + 1, high);
}
}
2.3.时间复杂度和稳定性
1.时间复杂度:O(n)* 递归深度(与二叉树树形类似)
①最好时间复杂度 O(nlogn)
②快时间复杂度 O(n^2)本来就有序,每次的划分很不均,递归深度小
2.空间复杂度:O(递归层数)
①已经有序:O(n^2)
②二分:O(logn)
3.稳定性:不稳定
4.适用:顺序表
3.王道课后题
//交换元素
void swap(int &i, int &j) {
int temp = i;
i = j;
j = temp;
}
//冒泡排序
void BubbleSort(int arr[], int n) {
int i = 1, head = 0, tail = n - 1;
for (i = 1; i <= n; i++) {
//奇数次排序
if (i % 2) {
for (int j = head; j < tail; j++) {
if (arr[j] > arr[j + 1]) swap(arr[j], arr[j + 1]);
}
head++;
}
//偶数次排序
else {
for (int j = tail; j > head; j--) {
if (arr[j] < arr[j - 1]) swap(arr[j], arr[j - 1]);
}
tail--;
}
}//for
}
时间最少——快速排序
void QuickSort(int arr[], int low, int high){
//pivot保存low的当前元素
int temp = arr[low];
while (low < high) {
//high的当前元素不是偶数,则移动到low
while (low < high && (arr[high] % 2)) high--;
arr[low] = arr[high];
//low的当前元素不是偶数,则移动到high
while (low < high && !(arr[low] % 2)) low++;
arr[high] = arr[low];
}
//将temp赋值给low
arr[low] = temp;
}
//交换函数
void swap(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
//划分和排序
void Partition(int arr[], int low, int high){
int pivot = random() % (high - low + 1);
swap(arr[low], arr[pivot]);
pivot = arr[low];
while (low < high){
while (low < high && arr[high] >= arr[pivot]) high--;
arr[low] = arr[high];
while (low < high && arr[low] <= arr[pivot]) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
//函数入口
void QuickSort (int arr[], int low, int high) {
if (low < high){
int qivot = Partition(arr, low, high);
QuickSort(arr, low, qivot - 1);
QuickSort(arr, qivot + 1, high);
}
}
//划分并且排序
int Partition(int arr[], int low, int high) {
int pivot = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
while(low < high&& arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
//快速函数入口
int QuickSort_SearchK(int arr[], int low, int high, int k) {
if (low < high) {
int pivot = Partition(arr, low, high);
//返回的数组下标为k,即为第k小元素
if (pivot == k) return arr[pivot];
//返回数组下标大于k,去左子表
else if (pivot > k) return QuickSort_SearchK(arr, low, pivot - 1, k);
//返回数组下标小于k,去右子表
else if (pivot < k) return QuickSort_SearchK(arr, pivot + 1, high, k);
}
//返回-1表示没找到
return -1;
}
int QuickSort_SearchK(int arr[], int low, int high, int k){
int low_temp = low, high_temp = high, pivot = arr[low];
//快速排序算法实现
while (low < high) {
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
//判断是否当前元素在数组中的位置是否与k相等
//相等则是第k小元素
if (low == k) return arr[low];
//小于则去右子表查找
else if (low < k) return QuickSort_SearchK(arr, low_temp, low - 1, k);
//大于则去左子表查找
else if (low > k) return QuickSort_SearchK(arr, low + 1, high_temp, k);
}
//交换数组元素
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
//0指代红,1指代白,2指蓝
void ColourSort(int arr[], int n) {
int i = 0, h = 0, t = n - 1;
//循环直到 i >= 尾指针t
while (i < t) {
//当前元素为0,与头指针交换
if (arr[i] == 0) {
swap(arr[i], arr[h]);
h++;
}
//当前指针为2,与尾指针交换
else if (arr[i] == 2) {
swap(arr[i], arr[t]);
t--;
}
//当前为白,往前移动一个元素
else i++;
}
}
1.使用快速排序排序数组A,快速排序特性:每轮确定一个元素在数组中的按顺序排列的大小位置
若n为奇数:n1 = n2 - 1,且A1的元素为A的数组下标0 - n1元素;n2为剩下元素
若n为偶数:n1 = n2,且A1的元素为A的数组下标0 - n1元素;n2为剩下元素
2.
//划分并排序
int QuickSort_Divide (int arr[], int n) {
int low = 0, high = n - 1;
//标记是否找到第n / 2小的元素
bool flag = false;
int high_temp = high, low_temp = low;
int pivot = arr[low];
while (!flag) {
int pivot = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivot) high--;
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) low++;
arr[high] = arr[low];
}
arr[low] = pivot;
if (low == n / 2) flag = true;
//当前元素并非n/2,更小则去右子表,更大则去左子表
//更新low,high,low_temp,high_temp
else if (low < n / 2) {
high = high_temp;
low_temp = low + 1;
low = low_temp;
}
else if (low > n / 2) {
low = low_temp;
high_temp = low - 1;
high = high_temp;
}
}//while
int s1 = 0, s2 = 0;
for (int i = 0; i < n / 2; i++) s1 += arr[i];
for (int i = n / 2; i < n; i++) s2 += arr[i];
return s2 - s1;
}