为了防止面试再次翻车,总结一下排序,并给出代码
快排
描述:
1.首先设定一个分界值,通过这个分界值将数组的值分到两边
2.将大于或等于分界值的数,放到数组分界值的右边。将小于或等于分界值的数,放到数组的左边。
3.对于分界值左边的数据,继续进行分界流程,然后对于分界值右边的数据,同样可以继续进程分界流程。
4.上述过程可以写成递归实现,先递归实现左侧部分排序,然后实现右侧部分排序。然后整个排序过程就完成了。
代码
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
void QuickSort(int array[],int start,int last)
{
int i=start;
//底端指针
int j=last;
//高端指针
int temp = array[i];
//二分指针,把temp作为分割整个区间底依据
if (i<j)
{
while(i<j)
{
while (i<j && array[j]>=temp)
j--;
//j找到右边第一个比a[i]小的数
if (i<j)
{
array[i] = array[j];
i++;
}
//把这个值放到低端指针上
//这个时候array[j]的值已经移动了
//这个时候应该从找到一个比temp大的值放到array[j]上
while (i<j && temp > array[i])
i++;
//然后从低端指针找到第一个比二分指针大的值
if (i<j)
{
array[j]=array[i];
//把低端指针的值放到高端指针上
//这个时候array[i]上的值已经移动
//下次循环,又会找到一个比temp小的值放到array[i]上
j--;
}
}
array[i]=temp;
//这样排序保证了i位置一定是正确的
//左排序
QuickSort(array,start,i-1);
//右排序
QuickSort(array,i+1,last);
}
}
int main(){
int a[100];
int n;
while(~scanf("%d",&n)){
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
QuickSort(a,1,n);
for (int i=1;i<=n;i++){
printf("%d ",a[i]);
}
cout<<endl;
}
return 0;
}
冒泡排序
冒泡排序相当于就是每次把最小的值(或者最大的值) 通过连续的和相邻的进行比较,把大的值往右边放,保证右边一定是有一部分是已经排序好的。
最坏时间复杂度是O(n^2)
最优时间复杂度是O(n)
原因,我们如果发现整个序列都是有序的,没有一个位置需要进行大小的交换,那么这个序列一定是已经排好序的,比如1 2 3 4 5 这类,其实只需要O(N)就排序完成了
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
void Pop_sort(int array[],int len){
int didswap;
for (int i=1;i<=len;i++){
didswap=0;
//这一步做了判断
for (int j=1;j<=len-i;j++){
if (array[j+1]<array[j]){
swap(array[j+1],array[j]);
didswap=1;
}
}
if (didswap==0)
return ;
}
}
int main(){
int a[10];
int n;
while(~scanf("%d",&n)){
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
Pop_sort(a,n);
for (int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
return 0;
}
选择排序
这个排序其实很简单,首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
最差时间复杂度是O(n^2)
最好时间复杂度还是(n^2)
因为循环每次都要从左往右扫去找第k小的数,放在第K个位置,无法进行优化
代码
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
void SelectSort(int array[],int len){
for (int i=1;i<=len;i++){
int minIndex=i;
for (int j=i+1;j<=len;j++){
if (array[j]<array[minIndex]){
swap(array[j],array[minIndex]);
}
}
}
}
int main(){
int a[10];
int n;
while(~scanf("%d",&n)){
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
SelectSort(a,n);
for (int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
return 0;
}
归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并得到完全有序的序列;
最坏复杂度:O(logn)
最优复杂度:O(logn)
由于本排序每次都把一个区间分成两端,类似于二分,在分区的操作是O(logn),加上遍历到底的交换,总复杂度是O(n),复杂度是O(n*logn),并且复杂度稳定。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int temp[100];
void Merge(int a[],int left,int right){
int i=left;
int mid=(left+right)/2;
int j=mid+1;
int n=0;
int lenth=right-left;
while(i<=mid && j<=right){
if (a[i]>a[j]){
temp[n++]=a[j];
j++;
}else {
temp[n++]=a[i];
i++;
}
cout<<"ss"<<endl;
}
while(i<=mid){
temp[n++]=a[i++];
}
while(j<=right){
temp[n++]=a[j++];
}
for (int k=0;k<=lenth;k++){
a[left+k]=temp[k];
}
}
void merge_sort(int a[],int left,int right){
int mid=(left+right)/2;
if (left<right){
//这里注意,是先要把数字分治到底部
merge_sort(a,left,mid);
merge_sort(a,mid+1,right);
Merge(a,left,right);
}
}
int main(){
int a[10];
int n;
while(~scanf("%d",&n)){
for (int i=0;i<n;i++){
scanf("%d",&a[i]);
}
cout<<n<<endl;
merge_sort(a,0,n-1);
for (int i=0;i<n;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
return 0;
}