机试刷题笔记——排序篇


整理了常见的几种排序类型,基于一维动态数组进行实现,均为升序排列。

排序类型平均时间复杂度最好时间复杂度最坏时间复杂度空间复杂度稳定性
冒泡排序O(N^2)O(N^2)O(N^2)O(1)稳定
插入排序O(N^2)O(N)O(N^2)O(1)稳定
选择排序O(N^2)O(N^2)O(N^2)O(1)稳定
希尔排序O(N^(3/2))O(N)O(N^2)O(1)不稳定
堆排序O(NlogN)O(NlogN)O(NlogN)O(1)不稳定
归并排序O(NlogN)O(NlogN)O(NlogN)O(N)稳定
快速排序O(NlogN)O(N^2)O(NlogN)O(logN)不稳定

冒泡排序

过程:
第一个元素与第二个元素比较大小,如果第一个元素大于第二个元素则调换位置.
比较第二个元素和第三个元素的大小,如果第二个元素大于第三个元素则调换位置.
依次类推,进行两两元素的比较和交换,最终最大的元素排在了最后面.
循环上述操作,直至排完所有元素.

//普通版本
void bubblesort(vector<int>&a)
{
for(int i =0 ;i<a.size();++i)
{
for(int j = 0;j<n-1-i;++j)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
}}}}
//优化一,设置flag寻找第一个排序完的的元素
void bubblesort(vector<int>&a)
{
int n = a.size();
int flag = n;
int stop_pos;
for(int i =0 ;i<n;++i)
{
stop_pos = flag-1;
for(int j =0 ;j<stop_pos;++j)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag = j+1;
}}}}
//优化二,使用flag判断是否有序
void bubblesort(vector<int>&a)
{
int n = a.size();
int flag;
for(int i =0;i<n;++i)
{
flag = true;
for(int j =0 ;j<n-1;++j)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag = false;
}
}
if(flag)
break;
}
}
//优化三,结合上述两种优化
void bubblesort(vector<int>%a)
{
int n = a.size();
int flag,stop_pos,order_pos;
for(int i= 0; i<n;++)
{
flag = true;
stop_pos = order_pos -1;
for(int j =0 ;j<stop_pos;++j)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag= false;
order_pos = j=1;
}
}
if(flag)
break;
}
}

插入排序

过程:
对于第K个元素,将该元素的值存储在零时变量中,比较第前一个元素与该元素的大小,如果大于该元素就将前一个元素往后移动一步;
比较前面第二个元素与该元素的大小,如果大于该元素就将前第二个元素往后移动一步;
重复上述过程直到找到小于等于原来第K个元素(保存在零时变量中)的位置,并将第K个元素插入到这个元素的后面。或者找不到小于等于第K个元素的位置,就将原来第K个元素插入到数组的首地址。

void insertsort(vector<int>&a)
{
int n = a.size();
for(int i =0 ; i<n;++i)
{
int insert_num = a[i],j,
for(j =i-1;j>=0;--j)
{
if(insert_num<a[j])
a[j] = a[j+1];
else
break;
}
a[j+1] = insert_num;
}}

选择排序

过程:
在一个无序数组中选择出每一轮中最值元素,然后把这一轮中最前面的元素和min交换,最后面的元素和max交换;然后缩小范围,重复上面步骤,最终得到有序序列(升序)。

void selectsort(vector<int>&a)
{
for(int i =0 ;i <a.size();++i)
{
int front = i;
for(int j =i +1;j<a.size();++j)
{
if(a[index] >a[j])
{
index = j;
}}
swap(a[front],a[i]);
}
}

希尔排序

希尔排序是在插入排序的基础上进行发展的,通过一个希尔增量先排序一定间隔的数据。
排序过程
插入排序每次与前面一个比较,然后再往前一个,而希尔排序每次往前K个;
当增量为1的时候,希尔排序与插入排序就完全是一样的过程;
所以代码也很好实现,将插入排序中增1的地方改为增K就行。

void shellsort(vector<int>&a)
{
int n = a.size();
for(int increment = n/2;increment > 0;increment/=2)
{
for(int i = increment; i<n;++i)
{
int insert_num =a[i],j;
for(j =i-increment;j>=0;j-=increment)
{
if(a[j]>insert_num)
{
a[j+increment] = a[j];
}
else
break;
}
a[j+increment] = insert_num;
}
}
}

堆排序

建立最大堆,建堆的过程是从N/2的位置开始,将父节点与子节点比较,如果子节点大于父节点则交换。为什么是N/2,是因为堆中树叶的个数是N/2。
从堆中删除堆顶元素,对于最大堆而言,堆顶元素也就是最大元素。每删除一个堆顶元素,就将堆顶元素放在数组的后面,因为每删除一个就出现一个空位,所以数组后面是有地方存放的。
进行N-1次的删除以后,整个数组就是排序的状态了。

//建立大顶堆
void make_headp(vector<int>&a,int n )
{

for(int i = n- 1,i>0;--i)
{
//奇数
if(i&1 && a[i]> a[(i-1)/2])
swap(a[i],a[(i-1)/2]);
else if(i&1 == 0 && a[i] > a[(i-2)/2])
swap(a[i],a[(i-2)/2]);
}
}
//堆排序
void heapsort(vector<int>&a)
{
int n = a.size();
while(n)
{
make_heap(a,n);
--n;
swap(a[0],a[n])
}
}

归并排序

过程:
将一个大的数组分为N1和N2,然后分别对两个数组进行排序,最后通过归并将整个数组合并为有序数组。

vector<int> merge(vector<int>&a, int left,int right)
{
//如果只有一个元素,则返回该元素
if(left == right)
return vector<int>(1,a[left]);
int mid = (right +  left)/2;
vector<int> l = merge(a,left,mid);
vector<int> r = merge(a,mid+1,right);
vector<int> res;
int ll= 0, rr= 0;
while(ll<l.size()&&rr<r.size())
{
if(l[ll]<r[rr])
res.push_back(l[ll++]);
else
res.push_back(r[rr++]);
}
while(ll<l.size())
res.push_back(l[ll++]);
while(rr<r.size())
res.push_back(r[rr++]);
return res;
}
void mergesort(vector<int>&a)
{
a = merge(a,0,a.size()-1);
}

快速排序

过程:
选择一个枢纽元,可以选择首,尾,中三个数的中位数作为枢纽元;
将枢纽元位置与数组的尾地址进行交换;
定义两个指针,P1指向数组首地址,P2指向数组倒数第二个位置,P1所指元素的值与枢纽元比较,如果小于枢纽元则后移一位,如果大于就停下来。P1所指元素的值与枢纽元比较,如果大于枢纽元则前移一位,如果小于就停下来;
交换P1和P2所指向的元素;
重复3和4直到P1大于P2;
对数组的分割过程同样采用递归的方法。

//普通快排
void quicksort(vector<int>&a,int start,int end)
{
//定义退出条件
if(start >= end)
return;
//选择开始和结束位置以及中间值
int l = start,r = end;
int priovt = a[(start+end)>>1];
while(l<=r)
{
//右集合
while(l<=r&&a[r]>priovt)
--r;
//左集合
while(l<=r&&a[r]<priovt)
++l;
if(l>=r)
{
swap(a[l++],a[r--]);
}
}
//排序左子集
quicksort(a,start,r);
//排序右子集
quicksort(a,l,end);
}
//改进的快排,针对左右数组不对称的情况进行改良
//选择首、中、后三个位置的中位数作为判断指标
int findmiddle(int first,int mid,int end)
{
if(a>= b ^ a <=c)
return a;
else if (b>=a ^ b<=c)
return b
else 
return c;
}

void quicksort(vector<int>&a,int start,int end)
{
//中位数
int pivot = findmiddle(a[start],a[(start+end)/2],a[end]);
int l =start,r = end;
while(l<=r)
{
while(l<=r&&a[r] > pivot)
--r;
while(l<=r && a[l]<pivot)
++l;
if(l<=r)
swap(a[r++],a[l++]);
}
quicksort(a,start,r);
quicksort(a,l,end);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值