赞
踩
原理:
依次比较两个相邻的元素,如果它们顺序错误就把它们交换过来。
时间复杂度:
若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:C min = n-1 ,M min =0;
所以,冒泡排序最好的时间复杂度为 O(n)。
若初始文件是反序的,需要进行 n-1 趟排序。每趟排序要进行 n-i 次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
冒泡排序的最坏时间复杂度为O(n^2)
综上,因此冒泡排序总的平均时间复杂度为 O(n^2)
稳定性:
冒泡排序是一种稳定排序算法。
代码实现:
public static void sort(int[] array){ for(int i=0;i<array.length-1;i++){ for(int j=0;j<array.length-1;j++){ if(array[j]>array[j+1]){ int tmp=0; tmp=array[j]; array[j]=array[j+1]; array[j+1]=tmp; } } } } public static void main(String[] args){ int[] array={10,5,3,7,6}; sort(array); System.out.println(Arrays.toString(array)); }
代码优化:
(1)对循环次数进行优化:
在第一轮比较完之后,会找到元素的最大值,放在最右边,这样在下轮比较时就不用再比较第一个元素了,所以内部循环可以优化为 j < array.length- 1 - i
(2)对排序完成进行优化:
对于状态已经变为按顺序进行排列的元素,这时候就已经排序完成了,不需要再进行循环遍历交换了,可以使用一个标志位flag来判断排序是否已经完成了。如果执行交换代码了,则证明还需要排序,flag=false,如果没有执行交换代码,不需要再进行排序了,直接return。
public static void sort(int[] array){ for(int i=0;i<array.length-1;i++){ boolean flag=false; for(int j=0;i<ayyay.length-i-1;j++){ if(array[j]>array[j+1]){ int tmp=0; tmp=array[j]; array[j]=array[j+1]; array[j+1]=tmp; flag=true; } } if(flag==false){ return; } } }
原理:
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的开头。以此类推,直到全部待排序的数据元素的个数为零。
时间复杂度:
最好情况是,已经有序,交换0次。
最坏情况交换n-1次,逆序交换n/2次。
稳定性:
选择排序是不稳定的排序方法
代码实现:
public static void selectSort(int[] nums){
for(int i=0;i<nums.length-1;i++){
int tmp=i;
for(int j=i+1;j<nums.length;j++){
if(nums[j]<nums[tmp]){
swap(nums,j,tmp);
}
}
}
}
public static void swap(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
代码优化:
在一次循环后,将最小值放在最前端,最大值放在最后端(或者最小的在最后端,最大的在最前端),这样可以实现循环减半。
public static void sort(int[] nums){ if(nums.length<2){ return; } int left=0;//每次排序最左位置 int right=nums.length-1;//每次排序最右位置 int minpos=0;//每次选出的最小值的数组下标 int maxpos=0;//每次选出的最大值的数组下标 while(left<right){ for(int i=left;i<=right;i++){ //找出值更小的元素,记下数组下标 if(nums[i]<nums[minpos]){ minpos=i; } //找出值更大的元素,记下数组下标 if(nums[i]>nums[maxpos]){ maxpos=i; } //如果本次循环的最小元素不是最左边的元素,则交换他们的位置 if(minpos != left){ swap(nums,minpos,left); } //如果maxpos位置是left,则maxpos的值要修改为minpos(因为在上面已将left位置的值替换为minpos位置的值)(下面图形解释) if(maxpos==left){ maxpos=minpos; } //如果本次循环的最大元素不是最右边的元素,则交换他们的位置 if(maxpos != right){ swap(nums,right,maxpos); } left++; right--; } } } public staic void swap(int[] nums,int i,int j){ int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; }
此段代码解释:
if(maxpos==left){
maxpos=minpos;
}
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
9 | 5 | 2 | 3 | 4 | 7 |
第一次循环:
left=0
right=5
minpos=2
maxpos=0 (maxpos=left)
if(minpos != left){
swap(nums,minpos,left);
}
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
2 | 5 | 9 | 3 | 4 | 7 |
此时因为left和minpos的元素进行了交换,而恰好最开始maxpos=left,所以这个最大元素的位置被换到了minpos的位置上,所以要设置maxpos=minpos
原理:
在待排序的元素中,假设前面n-1个元素已经是排序好的,现在将第n个数据插入到前面已经排好的序列中,然后找到合适的位置,使得插入的第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序。
时间复杂度:
最好情况下,当前数组是有序的,只需要比较n-1次就可,时间复杂度为O(N)
最坏情况下,排序数组是逆序,时间复杂度是O(N^2)
稳定性:
如果待排序的序列中存在两个或两个以上具有相同关键词的数据,排序后这些数据的相对次序保持不变,即它们的位置保持不变,通俗地讲,就是两个相同的数的相对顺序不会发生改变,则该算法是稳定的;如果排序后,数据的相对次序发生了变化,则该算法是不稳定的。
代码实现:
public static void sort(int[] nums){
for(int i=1;i<nums.length;i++){
int valueToSort=nums[i];
int j=i;
while(j>0 && nums[j-1]>valueToSort){
nums[j]=nums[j-1];
j--;
}
nums[j]=valueToSort;
}
}
原理:
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
时间复杂度:
稳定性:
代码实现:
//双指针法 private int sort(int[] nums,int startIndex,int endIndex){ int pivot=nums[startIndex]; int leftPoint=startIndex; int rightPoint=endIndex; while(leftPoint < rightPoint){ //从右向左找到比pivot小的数据 while(leftPoint<rightPoint && nums[rightPoint]>pivot){ rightPoint--; } //从左向右找到比pivot大的数据 while(leftPoint<rightPoint && nums[leftPoint]<=pivot){ leftPoint++; } //没有过界则交换 if(leftPoint<rightPoint){ int temp=nums[leftPoint]; nums[leftPoint]=nums[rightPoint]; nums[rightPoint]=temp; } } //最终将分界值与当前指针数据交换 nums[startIndex]=nums[rightPoint]; nums[rightIndex]=pivot; //返回分界值所在下标 return rightPoint; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。