直接插入排序,选择排序,冒泡排序,快速排序的代码

学了该数据结构,排序当然少不了,在完成课后习题时,觉得把代码放上来,方便以后查看。
1、直接插入排序
直接插入插排的基本思想是:当插入第i(i >= 1)时,前面的V[0],V[1],……,V[i-1]已经排好序。这时,用V[I]的排序码与V[i-1],V[i-2],…的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的元素向后顺移。

  在图一中给出了直接插入排序的过程。设在元素表中有n = 6个元素,为了使描述书简介直观,在图中只画出各元素的排序码。其中有两个排序码相同,前一个直接写为25,后一个标记为25*。假定其中V[0],…,V[i-1]已经是一组有序的元素,V[i],V[i+1],……,V[n-1]是带插入的元素。排序过程从i = 1起,每执行完一趟之后i增加1,把第i各元素插入到前面有序的元素序列中去,使插入后的元素序列V[0],V[1],……,V[i-1]仍保持有序。

在这里插入图片描述
直接插入排序时间复杂度分析
若设待排序的元素个数为n,则该算法会执行n-1趟。因为排序码比较次数和元素移动次数与元素排序码的初始排列有关,所以在最好的情况下,即在排序前元素已经按排序码大小从小到大排好了,每趟只需与前面的有序元素序列的最后一个元素的排列吗进行比较,总的排序码比较次数为n-1,元素移动次数为0。而在最差的情况下,及第i趟时第i个元素必须与前面i个元素都做排序码的比较,并且每做一次就叫就要做一次数据移动,则在最坏的情况下排序码的排序码比较次数KCN和元素移动次数RMN分别为:

在这里插入图片描述

从上面的讨论可以看出来,直接插入排序的运行时间和待排序元素的原始排序顺序密切相关。如果待排序元素序列中出现各种可能排列的概率相同,则可以取上述最好和最坏情况的平均情况,在平均情况下的排序码比较次数和元素移动次数约为n2/4。因此,直接插入排序的时间复杂度为O(n2)。并且直接插入排序是一种稳定的排序方法。

代码如下:
public static void insert(int[] n)
{
int i,j;
int temp;
for(i=1;i<n.length;i++)
{
temp=n[i];
j=i-1;
while(j>=0&&temp<n[j])
{
n[j+1]=n[j];
j–;
}
n[j+1]=temp;
}
}
2、选择排序
基本思想:假设排序表为 L[1…n] ,第i趟排序即从L[i,n] 中选择关键字最小的元素与 L(i) 交换,每一趟排序可以确定一个元素的最终位置,这样经过 n-1 趟排序就可以使整个排序表有序。
空间效率为O(1)
元素移动次数很少,当表有序时移动次数为0,但比较的次数与表的次序无关,所以时间复杂度始终为O(n2)
不稳定的算法
代码如下:
public static void select(int[] n)
{
int i,j,k;
int temp;
for(i=0;i<n.length-1;i++)
{
k=i;
for(j=i+1;j<n.length;j++)
if(n[j]<n[k])
k=j;
if(k!=i)
{
temp=n[k];
n[k]=n[i];
n[i]=temp;
}
}
}
3、冒泡排序
从数组头部开始,不断比较相邻的两个元素的大小,让较大的元素逐渐往后移动(交换两个元素的值),直到数组的末尾。经过第一轮的比较,就可以找到最大的元素,并将它移动到最后一个位置。
第一轮结束后,继续第二轮。仍然从数组头部开始比较,让较大的元素逐渐往后移动,直到数组的倒数第二个元素为止。经过第二轮的比较,就可以找到次大的元素,并将它放到倒数第二个位置。
以此类推,进行 n-1(n 为数组长度)轮“冒泡”后,就可以将所有的元素都排列好。

整个排序过程就好像气泡不断从水里冒出来,最大的先出来,次大的第二出来,最小的最后出来,所以将这种排序方式称为冒泡排序(Bubble Sort)。下面我们以“3 2 4 1”为例对冒泡排序进行说明。第一轮 排序过程3 2 4 1 (最初)2 3 4 2 (比较3和2,交换)2 3 4 1 (比较3和4,不交换)2 3 1 4 (比较4和1,交换)第一轮结束,最大的数字 4 已经在最后面,因此第二轮排序只需要对前面三个数进行比较。第二轮 排序过程2 3 1 4 (第一轮排序结果)2 3 1 4 (比较2和3,不交换)2 1 3 4 (比较3和1,交换)第二轮结束,次大的数字 3 已经排在倒数第二个位置,所以第三轮只需要比较前两个元素。第三轮 排序过程2 1 3 4 (第二轮排序结果)1 2 3 4 (比较2和1,交换)至此,排序结束。
冒泡排序的最坏时间复杂度为O(n^2)
综上,因此冒泡排序总的平均时间复杂度为 O(n^2)
冒泡排序是一种稳定排序算法。
代码如下:
public static void bubble(int[] n)
{
for(int i=0;i<n.length-1;i++) //比较,找出最小的记录
for(int j=n.length-1;j>i;j–)
if(n[j]<n[j-1])
{//交换,将最小的关键字前移
int t=n[j];
n[j]=n[j-1];
n[j-1]=t;
}
}
4、快速排序
(1) 我们从待排序的记录序列中选取一个记录(通常第一个)作为基准元素(称为key)key=arr[left],然后设置两个变量,left指向数列的最左部,right指向数据的最右部。
在这里插入图片描述
(2) key首先与arr[right]进行比较,如果arr[right]<key,则arr[left]=arr[right]将这个比key小的数放到左边去,如果arr[right]>key则我们只需要将right–,right–之后,再拿arr[right]与key进行比较,直到arr[right]<key交换元素为止。
在这里插入图片描述
(3) 如果右边存在arr[right]<key的情况,将arr[left]=arr[right],接下来,将转向left端,拿arr[left ]与key进行比较,如果arr[left]>key,则将arr[right]=arr[left],如果arr[left]<key,则只需要将left++,然后再进行arr[left]与key的比较。
在这里插入图片描述
(4) 然后再移动right重复上述步骤
在这里插入图片描述
(5) 最后得到 {23 58 13 10 57 62} 65 {106 78 95 85},再对左子数列与右子数列进行同样的操作。最终得到一个有序的数列。
具体代码如下:
public static void quick(int[] n,int s,int t)//对n[s]至n[t]的元素进行快速排序
{
int i=s,j=t;
int temp;
if(s<t)
{
temp=n[s];//第一个作为基准
while(i!=j)//从区间两端交替向中间扫描,到i=j为止
{
while(j>i&&n[j]>temp)
j–; //从右向左扫描,找到一个小于temp的n[j];
n[i++]=n[j]; //交换
while(j>i&&n[i]<temp)
i++; //从左向右扫描,找到一个大于temp的n[j];
n[j–]=n[i]; //交换
}
n[i]=temp;
quick(n,s,i-1);//对左区间进行排序
quick(n,i+1,t);//对右区间进行排序
}
}

在这里要感谢其他博客,借鉴了他们的一些解析,让我更加明白这些排序的算法。

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值