整理一份适合面试的八大排序算法,参考:
https://blog.csdn.net/csdn_baotai/article/details/80293679
https://blog.csdn.net/ysunflower/article/details/80425788
https://blog.csdn.net/prstaxy/article/details/8166360(归并排序)
https://blog.csdn.net/Koala_Tree/article/details/79958965 (十大排序)
特此感谢!
比较类排序:通过比较来决定元素间的相对次序。
时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
非比较排序,不通过比较来决定元素间的相对次序
时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。
稳定:如果一个数a原本在b前面,而a = b,排序之后一个a仍然在b的前面。
原始代码:
void bubbleSort(int arr[],int len)
{
for(int i=0;i<len-1;++i)
for(int j=0;j<len-1-i;++j)
{
if(arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
}
改进代码:
void bubbleSort1(int arr[],int len)
{
bool isSwap = true;
for(int i=0;i<len-1 && isSwap;++i)
{
isSwap = false;
for(int j=0; j<len-1-i;++j)
{
if(arr[j]>arr[j+1])
{
isSwap = true;
swap(arr[j],arr[j+1]);
}
}
}
}
void selectSort(int arr[],int len)
{
int minIndex;
for(int i=0;i<len-1;++i)
{
minIndex = i;
for(int j=i+1;j<len;++j)
{
if(arr[j]//最小
minIndex = j;
}
if(i != minIndex)
swap(arr[i],arr[minIndex]);
}
}
void insertSort(int arr[],int len)
{
int preIndex,current;
for(int i=1;i1;
current = arr[i];
while(preIndex>=0 && arr[preIndex]>current)
{
arr[preIndex+1] = arr[preIndex];
preIndex--;
}
arr[preIndex+1] = current; //合适位置
}
}
递归和非递归版本
#include
#include
#include
using namespace std;
void Merge(int arr[], int low, int mid, int high)
{
//low为第一有序区间的第一个元素,mid为第一有序区间的最后一个元素
//mid+1为第二有序区间的第一个元素,high为第二有序区间的最后一个元素
int i = low, j = mid + 1;
int k = 0; //合并数组索引
int *temparr = new (nothrow) int[high - low + 1];
if (!temparr)
{
cout << "Error";
exit(1);
}
//顺序选取两个有序区的较小元素,存储到t数组中
while (i<=mid && j<=high)
{
if (arr[i] <= arr[j])
temparr[k++] = arr[i++];
else
temparr[k++] = arr[j++];
}
//若比较完之后,第一个有序区仍有剩余,则直接复制到t数组中
while (i<=mid)
{
temparr[k++] = arr[i++];
}
while (j <= high)
{
temparr[k++] = arr[j++];
}
//将排好序的t存回arr中low到high区间
for (i = low, k = 0; i <= high; i++, k++)
arr[i] = temparr[k];
delete[] temparr; //删除指针,由于指向的是数组,必须用delete []
}
void MergeSortRecursion(int arr[], int low, int high)
{
//当low==high时,分治完成,要注意递归结束条件
if (low < high)
{
int mid = (low + high) / 2;
MergeSortRecursion(arr, low, mid);
MergeSortRecursion(arr, mid + 1, high);
Merge(arr, low, mid, high); //分治后排序
}
}
//非递归实现
void MergeSortIteration(int arr[], int n)//参数和递归略不同,n代表数组中元素个数,即数组最大下标是n-1
{
//需要考虑第2个序列个数不足的情况
int size = 1, low, mid, high;
while (size <= n - 1)
{
low = 0;
while (low + size < n )
{
mid = low + size - 1;
high = mid + size;
if (high>n - 1)//第二个序列个数不足size
high = n - 1;
Merge(arr, low, mid, high);//调用归并子函数
cout << "low:" << low << " mid:" << mid << " high:" << high << endl;//打印出每次归并的区间
low = high + 1;//下一次归并时第一关序列的下界
}
size *= 2;//范围扩大一倍
}
}
int main() {
int x[] = { 6,5,3,1,8,7,2,0,4 };
MergeSortRecursion(x, 0, 8);
for (int i = 0; i<9; i++)
cout << x[i] << " ";
cout << endl;
int x1[] = { 6,5,3,1,8,7,2,0,4 };
MergeSortIteration(x1, 9);
for (int i = 0; i<9; i++)
cout << x1[i] << " ";
getchar();
return 0;
}
快速排序是基于Partition的递归,这里参考我之前的文章《基于Partition函数实现快排》
1)从序列中任意选一个元素作为基准,将小于等于基准的元素放到基准前,将大于等于基准的元素放到基准后。
2) 一趟快速排序
3)接下来分别对基准前后两个子序列重复上述步骤。
递归终止条件: begin==end。
最坏情况时,两边极度不均衡(有序序列),此时退化为冒泡排序。
改进法:三者取中法,随机取值等,尽量使两边均衡。
int index = rand() % (end - start + 1) + start; // 随机选择基准
swap(nums[index], nums[end]);
#include
#include
#include
using namespace std;
//Two Pointers思想的分割函数(begin为0,end为n-1)
int Partition(vector<int> &nums, int begin, int end)
{
int pivot = nums[begin];//第一个记录作为枢轴(也可是在begin和end之间的随机数)
while (begin < end)
{
while (begin < end && nums[end] >= pivot)
{
end--;
}
nums[begin] = nums[end];//尾部找到小于pivot的值,移到低端
while (begin < end && nums[begin] <= pivot)
{
begin++;
}
nums[end] = nums[begin];//头部找到大于pivot的值,移到高端
}
nums[begin] = pivot;//枢轴基准归位
return begin;
}
void QuikSort(vector<int> &nums,int begin, int end)
{
if (end > begin)
{
int index = Partition(nums, begin, end);
QuikSort(nums, begin, index-1);
QuikSort(nums, index + 1,end);
}
}
int main() {
vector<int> vec{ 6,5,3,1,8,7,2,0,4 };
QuikSort(vec, 0, 8); //最大索引
for (int i = 0; i<9; i++)
cout << vec[i] << " ";
getchar();
return 0;
}
参考了:堆排序
void HeapAdjust(vector<int> &nums, int parent, int length)
{
int root = nums[parent];
int child = 2 * parent + 1;
while (child//若有右孩子,并且右孩子值大于左孩子值,则选取右孩子结点
if (child + 1 < length && nums[child] < nums[child + 1])
child++;
if (root >= nums[child])
break; //找到合适位置时跳出
//把较大结点赋值给父节点
nums[parent] = nums[child];
//选取孩子大节点更新为父节点(对有影响的分支继续)
parent = child;
child = 2 * parent + 1;
}
//安插合适位置
nums[parent] = root;
}
void HeapSort(vector<int> &nums)
{
int len = nums.size();
//建堆
for (int i = len / 2; i >= 0; --i)
HeapAdjust(nums, i, len);
for (int i = len - 1; i > 0; --i)
{
//最后一个元素和堆顶交换
swap(nums[0], nums[i]);
HeapAdjust(nums, 0, i);
}
}
待完成