文章目录
- 前言
- 1 冒泡排序
- 2 选择排序
- 3 插入排序
- 4 快速排序
- 5 归并排序
- 6 堆排序
- 7 希尔排序
前言
算法动画
时间复杂度分析
从小到大排序
1 冒泡排序
被动的将最大值送到最右边
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
原地修改数组:
void bubbleSort(vector<int>& nums) {
int len = nums.size();
for (int i = 0; i < len - 1; ++i) { // 外层只需n-1
for (int j = 0; j < len - 1 - i; ++j) {
if (nums[j] > nums[j + 1]) // 最大的放在数组最右
swap(nums[j], nums[j + 1]);
}
}
}
优化:算是一种剪枝
假如从开始的第一对到结尾的最后一对,相邻的元素之间都没有发生交换的操作,这意味着右边的元素总是大于等于左边的元素,此时的数组已经是有序的了,我们无需再对剩余的元素重复比较下去了。
void bubbleSort2(vector<int>& nums) {
int len = nums.size();
bool flag = false;
for (int i = 0; i < len - 1; ++i) {
flag = false;
for (int j = 0; j < len - 1 - i; ++j) {
if (nums[j] > nums[j + 1]) {
flag = true;
swap(nums[j], nums[j + 1]);
}
}
if (!flag)//说明没有交换,则表明[0,len-i-1]已经是有序的了
break;
}
}
2 选择排序
主动将最小值送到最左边
void selectSort(vector<int>& nums) {
int len = nums.size();
int minIndex = 0;
for (int i = 0; i < len; ++i) {
minIndex = i;
for (int j = i + 1; j < len; ++j) {
if (nums[j] < nums[minIndex]) minIndex = j;
}
swap(nums[i], nums[minIndex]);
}
}
3 插入排序
与选择排序思路一致,从左到右排序
void insertionSort(vector<int>& nums) {
int len = nums.size();
for (int i = 1; i < len; ++i) {
int n = i;
while(n > 0){
if(nums[n-1] > nums[n])
swap(nums[n], nums[n-1]);
else
break; // 左边的数组都是有序的了
n--;
}
}
}
4 快速排序
时间复杂度O(N*log(N))
nums = [15,19,2,18,24,4,20]
选择一个区间,将最左边的元素15作为中间点元素,然后将数组分成两个区间:
小于等于15的元素放其左侧,大于15的元素放其右侧
[2, 4]
,[15]
,[19, 18, 24, 20]
。
然后将这两个区间[2, 4]
与[19, 18, 24, 20]
按照相同的步骤(选最左侧元素。。。)
退出条件:
如果区间长度为1,直接归位
双指针递归法
1、输入输出
void quickSort(vector<int>& nums, int left, int right)
2、退出条件
if(left > right) return;
3、单层逻辑
首先存储这个区间的left
和right
指针,找到最左边元素nums[left]
int front = left;
int last = right;
int key = nums[left];
然后根据key
值放元素。
首先,从后往前走,选比key小的移到前面
// 直到选出一个不符合要求的
while (front < last && nums[last] > key)
last--;
if (front < last)
nums[front] = nums[last];
front++;
然后,从前往后走, 将比比key大的移到后面
// 直到选出一个不符合要求的
while (front < last && nums[first] <= key)
front++;
if (front < last)
nums[last] = nums[first];
last--;
最后,循环这两步
while(front < last){
从后往前走
从前往后走
}
nums[last] = key;
放完元素后进行递归,以key值的索引为两个区间的分界线
quickSort(nums, left, last - 1);
quickSort(nums, last + 1, right);
整合代码
// front 和 last 代表区间
void quickSort(vector<int>& nums, int front, int last) {
if(front >= last) return;
int left = front;
int right = last;
int key = nums[front];
while(left != right){
while(left != right && nums[right] > key) right--;
if(left != right){
nums[left] = nums[right];
left++;
}
while(left != right && nums[left] < key) left++;
if(left != right){
nums[right] = nums[left];
right--;
}
}
nums[left] = key;
quickSort(nums, front, right - 1);
quickSort(nums, right + 1, last);
}
5 归并排序
申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
设定两个指针,最初位置分别为两个已经排序序列的起始位置;
比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
重复步骤 3 直到某一指针达到序列尾;
将另一序列剩下的所有元素直接复制到合并序列尾。