排序算法笔记
一些总结的比较好的博客
1. 排序学习笔记
2. 部分排序方法的整理
各种排序思路总结
冒泡排序
1 外层循环将排序好的除去
2 内层循环将没排好的数组进行前后比较大小,每经过一个循环,最大的数都在最后面
稳定排序,时间复杂度O(N2)
void bubbleSort(vector<int> &arr) {
if(arr.size() == 0||arr.size() == 1)
return;
for( int i = arr.size()-1; i > 0 ; i--)
for( int j = 0; j < i ; j++)
{
if(arr[j] > arr[j+1])//此处是稳定的排序
swap(arr,j,j+1);
}//第一层下来最大的值已经冒泡到最上面的部分
return;
}
选择排序
先找到第一个数后的最小值,并将其与之交换(内层循环为找到最小值)
稳定,O(N2)
void selecttSort(vector<int> &arr) {
if(arr.size()==0||arr.size()==1)
return;
for(int i = 0; i < arr.size(); i++) {
int min = i;
for (int j = i + 1; j < arr.size(); j++) {
min = arr[min] < arr[j]? min : j;//找最小值,此时不是稳定排序的
}
swap(arr,i,min);
}
return;
}
插入排序
1 外层循环是将排好续的数组保留
2 内层循环是将拿到的数组进行插入
可以是稳定的,O(N2)
//版本一
void insertSort1(vector<int> &arr) {
if (arr.size() == 0 || arr.size() == 1)
return;
for (int i = 1; i < arr.size(); i++) {
for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
swap(arr, j, j + 1);//此处会认为是冒泡排序:冒泡排序的每一轮是相邻两个数进行比较,这个是每轮一个数和前已经有序的进行比较
}
}
return;
}
//版本二
/**
* 直接插入排序,先挪位置直接插入
* */
void sort::insertSort2(vector<int> &arr) {
int i,j;
for(i=1;i<arr.size();i++)
{
int temp=arr[i];
for(j=i;j>0&&arr[j-1]>temp;--j)
arr[j]=arr[j-1];
arr[j]=temp;
}
}
快速排序
递归分治
第一步: 将其划分两个区域 partition
第二分布: 左边递归,右边递归
可以做到稳定 O(NlogN)
void quicksort(int left, int right)
{
int i, j, t, temp;
if(left > right)
return;
temp = a[left]; //temp中存的就是基准数
i = left;
j = right;
while(i != j) { //顺序很重要,要先从右边开始找
while(a[j] >= temp && i < j)
j--;
while(a[i] <= temp && i < j)//再找右边的
i++;
if(i < j)//交换两个数在数组中的位置
swap(a[i],a[j])
}
//最终将基准数归位
a[left] = a[i];
a[i] = temp;
quicksort(left, i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1, right);//继续处理右边的 ,这里是一个递归的过程
}
荷兰国旗问题
排序成 左边小,中间相等,右边大的情况
第一步,利用两个指针,一个指向小的部分,一个指向大的部分
第二部分,当前指针遍历数组,如果小鱼目标值将起放到左边,大于放到右边,否则移动下标
快排的一部分,三路快排问题,不稳定 O(NlogN),
堆排序
第一步:建立大根堆,当前节点的大于父节点时,将其与之交换,向上调整
第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
第三步:做heapify向下调整:找到当前节点与左右子节点的最大值,交换后向下延伸
不稳定排序 O(N)
void push_down(vector<int> &heap, int size, int u) {
int t = u;
int left = 2 * u, right = 2 * u + 1;
while (left <= size && heap[left] > heap[t]) t = left;
while (right <= size && heap[right] > heap[t]) t = right;
if (t != u) {
swap(heap[t], heap[u]);
push_down(heap, size, t);
}
return;
}
void push_up(vector<int> &heap, int u) {
int father = u / 2;
while (father && heap[father] < heap[u]) {
swap(heap[father], heap[u]);
u = father;
father /= 2;
}
return;
}
void heap_sort(vector<int> &heap) {
heap.insert(heap.begin(), -1);
int n = heap.size() - 1;
for (int i = 1; i <= n; ++i) {
push_up(heap, i);
}
while (n) {
swap(heap[1], heap[n--]);
push_down(heap, n, 1);
}
heap.erase(heap.begin());
return;
}
归并排序
第一步:找到中点
第二步 : 递归左右子数组
第三步: 合并:此时分为三部分,先理好一遍没有的,再理好一边有的
稳定 O(NlogN)
void merge_module(vector<int> &nums, int l, int r) {
if (l >= r) return;
int mid = l + (r - l) / 2;
merge_module(nums, l, mid);
merge_module(nums, mid + 1, r);
static vector<int> tmp;
tmp.clear();
int i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (nums[i] <= nums[j])
tmp.push_back(nums[i++]);
else
tmp.push_back(nums[j++]);
}
while (i <= mid) tmp.push_back(nums[i++]);
while (j <= r) tmp.push_back(nums[j++]);
for (i = l, j = 0; i <= r; ++i, ++j) nums[i] = tmp[j];
return;
}
void merge_sort(vector<int> &nums) {
merge_module(nums, 0, nums.size() - 1);
return;
}