各种排序思路总结
/**
* 冒泡排序
* 1 外层循环将排序好的除去
* 2 内层循环将没排好的数组进行前后比较大小,每经过一个循环,最大的数都在最后面
* 稳定排序,时间复杂度O(N2)
* */
/**
* 选择排序
* 先找到第一个数后的最小值,并将其与之交换(内层循环为找到最小值)
* 不稳定,O(N2)
* */
/**
* 插入排序
* 1 外层循环是将排好续的数组保留
* 2 内层循环是将拿到的数组进行插入
* 可以是稳定的,O(N2)
* */
/**
* 快速排序
* 递归分治
* 第一步: 将其划分两个区域 partition
* 第二分布: 左边递归,右边递归
* 可以做到稳定 O(NlogN)
* */
/**
* 荷兰国旗问题
* 排序成 左边小,中间相等,右边大的情况
* 第一步,利用两个指针,一个指向小的部分,一个指向大的部分
* 第二部分,当前指针遍历数组,如果小鱼目标值将起放到左边,大于放到右边,否则移动下标
* 快排的一部分,三路快排问题,不稳定 O(NlogN),
* */
/**
* 堆排序
* 第一步:建立大根堆,当前节点的大于父节点时,将其与之交换,向上调整
* 第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
* 第三步:做heapify向下调整:找到当前节点与左右子节点的最大值,交换后向下延伸
* 不稳定排序 O(N)
* */
/**
* 归并排序
* 第一步:找到中点
* 第二步 : 递归左右子数组
* 第三步: 合并:此时分为三部分,先理好一遍没有的,再理好一边有的
* 稳定 O(NlogN)
* */
具体代码实现部分
//
// Created by yzm on 11/8/18.
//
#include "sort.h"
#include <stdlib.h>
/**
* 冒泡排序
* 1 外层循环将排序好的除去
* 2 内层循环将没排好的数组进行前后比较大小,每经过一个循环,最大的数都在最后面
*
* */
void sort::bubbleSort(vector<int> &arr) {
if(arr.size() == 0||arr.size() == 1)
return;
// for(int i = 0 ;i < arr.size(); i++)
// for(int j = i + 1; j < arr.size(), j++)
// {
// if(arr[i] > arr[j])//此处是稳定的排序
// swap(arr,i,j);
// }
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;
}
/**
* 选择排序
* 先找到第一个数后的最小值,并将其与之交换(内层循环为找到最小值)
*
* */
void sort::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 内层循环是将拿到的数组进行插入
*
* */
void sort::insertSort1(vector<int> &arr) {
if (arr.size() == 0 || arr.size() == 1)
return;
for (int i = 1; i < arr.size(); i++) {
// for(int j = i ; j > i ;j--)
// if(arr[i--] > arr[j])//可以实现稳定排序
// swap(arr,i,j);
//打牌,先找位置,找到了吧位置换过去
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 sort::quickSort1(vector<int> &arr,int L, int R) {
cout << L << "初始参数 "<<R<<endl;
if(L < R)
{
vector<int> p = partition(arr,L,R);
int left = p[0] - 1;//不能作为左值
int right = p[1] + 1;
cout<<p.size()<<" "<< left << " "<< right<<endl;
quickSort1(arr, L , left);
quickSort1(arr,right,R);
}
}
/**
* 荷兰国旗问题
* 排序成 左边小,中间相等,右边大的情况
* 第一步,利用两个指针,一个指向小的部分,一个指向大的部分
* 第二部分,当前指针遍历数组,如果小鱼目标值将起放到左边,大于放到右边,否则移动下标
* 快排的一部分,不稳定 O(NlogN)
* */
vector<int> sort::netherlandSort(vector<int> &arr, int L, int R, int target) {
int less = L-1;
int more = R+1;
int cur = L;
while (cur < more) {
if (arr[cur] < target) {
swap(arr, ++less, cur++);
} else if (arr[cur] == target) {
cur++;
} else {
swap(arr, cur, --more);
}
}
vector<int> a = {less+1,more-1};
return a;
}
//随机快速排序
void sort::quickSort2(vector<int> &arr, int L, int R) {
if(L < R)
{
int randomNum = L + rand()%(R - L + 1);//此处右边的表达是又不能做左值
swap(arr,randomNum,R);//产生随机数
vector<int> p = partition(arr,L,R);
int left = p[0] - 1;//不能作为左值
int right = p[1] + 1;
quickSort2(arr, L , left);
quickSort2(arr,right,R);
}
}
/**
* 堆排序
* 第一步:建立大根堆,当前节点的大于父节点时,将其与之交换,向上调整
* 第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
* 第三步:做heapify向下调整:找到当前节点与左右子节点的最大值,交换后向下延伸
* 不稳定排序 O(N)
* */
void sort::heapSort(vector<int> &arr) {
if(arr.size()==0||arr.size()==1)
return;
//第一步:建立大根堆
for(int i = 1; i < arr.size(); i++){
heapInsert(arr,i);
}
//第二步:将0位置的数与最后的位数交换,即根节点与尾节点交换
int heapSize = arr.size();
swap(arr , 0, --heapSize);
//做heapify调整
while(heapSize > 0){
heapify(arr, 0, heapSize);
swap(arr, 0, --heapSize);//每次将堆中最后位置的数与o位置的数进行交换
}
}
/**
* 归并排序
* 第一步:找到中点
* 第二步 : 递归左右子数组
* 第三步: 合并:此时分为三部分,先理好一遍没有的,再理好一边有的
* 稳定 O(NlogN)
* */
void sort::mergeSort(vector<int> &arr, int &L, int &R) {
if (L == R)
return;
int mid = L + ((R - L) >> 1);
mergeSort(arr, L, mid);
int lr = mid + 1;
mergeSort(arr, lr, R);
merge(arr, L, mid, R);//相等的先拷贝左边的,此时是稳定的
}
void sort:: swap(vector<int> &arr, const int &i,const int &j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return;
}
void sort::merge(vector<int> &arr,int &L,int &mid, int &R) {
/*
* 关于此函数遇到的问题
* 数组下表赋值必须提前分配数组空间,如果没有提前分配空间就必须使用push_back
* 这是因为push_back会自动new,new出来的会保存在堆上,否自在全栈上
* */
vector<int> help(R - L + 1);
//vector<int>help;//此时的数组大小为空 因此help[i]没有任何意义
int k = 0;
int i = L ;
int j = mid +1;
while (i <= mid&&j <= R)
{
// if( arr[i] < arr[j])
// help[k++] = arr[i++];
// else
// help[k++] = arr[j++];
help[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
//help.push_back(arr[i] < arr[j] ? arr[i++] : arr[j++]);
}
while (i <= mid) {
help[k++] = arr[i++];
//help.push_back(arr[i++])
}
while (j <= R) {
help[k++] = arr[j++];
//help.push_back(arr[j++])
}
for (k = 0; k < help.size(); k++) {
arr[L + k] = help[k];
}
}
vector<int> sort::partition(vector<int> &arr, int L, int R) {
int less = L - 1;
int more = R ;
while (L < more) {
if (arr[L] < arr[R]) {
swap(arr, ++less, L++);
} else if (arr[L] == arr[R]) {
L++;
} else {
swap(arr, L, --more);
}
}
swap(arr, more, R);
vector<int> a = {less+1,more};
return a;
}
/**
* 建立大根堆程序
* 当前节点的大于父节点时,将其与之交换
*
* */
void sort::heapInsert(vector<int> &arr, int index) {
while (arr[index] > arr[(index - 1)/2]){//当该节点的函数大于父节点时,将其与父节点进行交换
int temp = (index -1)/2;
swap(arr, index, temp);
index = temp;//向上走
}
}
void sort::heapify(vector<int> &arr, int index, int size) {
int left = index * 2 +1;//左子节点
while(left < size){//如果左节点存在
int largest = left +1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//如果右节点存在,找到左右节点的最大值
largest = arr[largest] > arr[index] ? largest : index;//找到该节点与子节点中最大值的部分
if (largest == index){//如果子节点相等则跳出循环
break;
}
swap(arr, index ,largest);//将最大值放在该节点上
index = largest;
left = index * 2 + 1;//向下继续延伸下去
}
}