冒泡排序
从序列的右边开始比较相邻的两个数字的大小,再根据比较结果交换两个数字的位置
时间复杂度:O(
n
2
n^2
n2)
vector<int> BubberSort(vector<int> &vecData)
{
for (size_t i = 0; i < vecData.size(); i++)
{
for (size_t j = 0; j < vecData.size()-i; j++)
{
if (vecData[j-1] > vecData[j])
{
Swap(vecData[j-1], vecData[j]);
}
}
}
return vecData;
}
选择排序
从待排序的数据中找到最小值,将其与序列最左侧的数字进行交换
时间复杂度:O(
n
2
n^2
n2)
vector<int> SelectSort(vector<int> &vecData)
{
for (size_t i = 0; i < vecData.size(); i++)
{
int iSelect = i;
for (size_t j = i+1; j < vecData.size(); j++)
{
if (vecData[j] < vecData[iSelect])
{
iSelect = j;
}
}
if (iSelect != i)
Swap(vecData[i], vecData[iSelect]);
}
return vecData;
}
插入排序
一种从序列左端开始依次对数据进行排序的算法,左侧的数据陆续归位,右侧数据是待排序的数据(有点像部分冒泡)
时间复杂度:O(
n
2
n^2
n2)
vector<int> InsertSort(vector<int> &vecData)
{
for (size_t i = 1; i < vecData.size(); i++)
{
for (size_t j = i; j > 0; j--)
{
if (vecData[j] < vecData[j-1])
{
Swap(vecData[j], vecData[j-1]);
}
}
}
return vecData;
}
堆排序
通过最大堆或最小堆,每次取出堆顶,对剩余节点进行堆调整,直到整个堆取完。
采用一维数组表示完全二叉树,假设当前节点为i,则其父节点为(i-1)/2取下整,左右子节点分别为2i+1和2i+2
时间复杂度:O( n l o g n nlogn nlogn),每轮取出最大的数据并重构堆所需时间为O( l o g n logn logn),总共需要进行n轮
基本思想
- 将无序序列建成一个堆
- 输出堆顶元素
- 以最后一个元素代替堆顶元素
- 将剩余的n-1个元素再调整成一个堆
- 重复执行,直到整个堆剩一个元素
void HeapAdjust(vector<int> &vecData, int index, int nLen)
{
int max = index;
int lchild = 2*index+1; //左子节点
int rchild = 2*index+2; //右子节点
//找出当前调整节点与子节点中的最大值
if (lchild < nLen && vecData[lchild] > vecData[max])
max = lchild;
if (rchild < nLen && vecData[rchild] > vecData[max])
max = rchild;
if (index != max) //需要调整
{
Swap(vecData[index], vecData[max]); //调整以后,被调整的子节点也需要进行递归调整
HeapAdjust(vecData, max, nLen);
}
}
vector<int> HeapSort(vector<int> &vecData)
{
int n = vecData.size();
for (int i = n/2-1; i>=0; i--)
{
HeapAdjust(vecData, i, n);
}
for(int i = n - 1; i>=0; i--)
{
Swap(vecData[0], vecData[i]); //把最大堆的最大值放到最后一个
HeapAdjust(vecData, 0, i); //那么需要调整的就剩下n-1个
}
return vecData;
}
归并排序
把序列分成长度相同的两个字序列,当无法继续往下分时,就对子序列进行归并
分治法,分解成子问题,再分别解决问题,再归并
时间复杂度O(
n
l
o
g
n
nlogn
nlogn)
void Merge(vector<int> &vec, int start, int mid, int end)
{
vector<int> vecTmp;
int i = start;
int j = mid+1;
while (i <= mid && j <= end) // 因为最终拆分到只剩一个,需要取等号
vecTmp.push_back(vec[i]<vec[j]? vec[i++]:vec[j++]);
while(i<=mid)
vecTmp.push_back(vec[i++]);
while(j<=end)
vecTmp.push_back(vec[j++]);
for (int k =0; k < vecTmp.size(); k++) //将排序后到临时缓冲区替换原始数组中正在排序的部分
vec[start+k] = vecTmp[k];
}
void MergeSort(vector<int> &vec, int start, int end)
{
if (start>=end)
return;
int mid = (start+end)/2;
MergeSort(vec, start, mid); //分治
MergeSort(vec, mid+1, end);
Merge(vec, start, mid, end); //合并
}
vector<int> MergeSort(vector<int> &vecData)
{
MergeSort(vecData, 0, vecData.size());
return vecData;
}
快排
首先在序列中随机选择一个基准值,将小于基准的数排到左侧,大于基准的拍到右侧
时间复杂度O(
n
l
o
g
n
nlogn
nlogn),如果每次选择的值都是最小值作为基准,则为O(
n
2
n^2
n2)
nt Partition(vector<int> &vecData, int lhs, int rhs)
{
int key = vecData[lhs];
while(lhs < rhs)
{
while (lhs<rhs && vecData[rhs] <= key)
rhs--;
if (lhs < rhs)
vecData[lhs] = vecData[rhs];
while(lhs < rhs && vecData[lhs] >= key)
lhs++;
if (lhs<rhs)
vecData[rhs] = vecData[lhs];
}
return lhs;
}
void QuickSort(vector<int> &vecData, int lhs, int rhs)
{
if (lhs >= rhs)
return;
int i = Partition(vecData, lhs, rhs);
QuickSort(vecData, lhs, i);
QuickSort(vecData, i+1, rhs);
}
vector<int> QuickSort(vector<int> &vecData)
{
QuickSort(vecData, 0, vecData.size()-1);
return vecData;
}