一、排序算法分类:
非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。
线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。
二、排序算法复杂度:
三、各种算法原理及其代码
1、冒泡排序(Bubble Sort):
a.动图演示
b.算法描述:
从左到右依次比较相邻两个元素的值,如果前面的数字比后面的数字大就交换位置(将大的数字移到后面),直到最后。
c.代码实现:
class BubbleSort{
public int[] Bubblesort(int[] arr){
//数组长度减一
for(int i=0;i<arr.length-1;i++){
//数组长度减一再减去外层循环的变量i
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
}
}
}
return arr;
}
}
2、选择排序(Selection Sort):
a.动图演示:
b.算法描述:
分为两个区域:有序区与无序区,将无序区第一个数字的小标定位最小值下标并与后面的数字想比较,如果后面的数值更小,将下标更新为最小值下标。如果最小值下标不是第一个值的下标就利用小标将无序区第一个数值与最小值进行交换。以此类推。
c.代码实现:
class SelectionSort{
public int[] Selectionsort(int[] arr){
//10位数字比较9次就可以排序完,所以是length-1
for(int i=0;i<arr.length-1;i++){
//需要一个最小值下标的临时变量,无序区的第一个数字的下标正好适合
int smallest_index=i;
//比较的时候是用无序区的第二个数字进行比较,所以是i+1;比较到最后的下标是9,所以是<length而不是<length-1
for(int j=i+1;j<arr.length;j++){
if(arr[j]<arr[smallest_index]){
smallest_index=j;
}
}
int temp=arr[i];
arr[i]=arr[smallest_index];
arr[smallest_index]=temp;
}
return arr;
}
}
3、插入排序(Insertion Sort)
a.动图演示:
b.算法描述:
分为两个区域:有序区与无序区,将无序区的第一个数字插入到有序区中(插入的时候从后往前插入,直到前面的数字比自己小为止)。
c.代码实现:
class InsertionSort{
public int[] Insertionsort(int[] arr){
//大循环次数比数组小一,且是从下标1开始而不是下标0
for(int i=1;i<arr.length;i++){
int preindex=i-1;
int current=arr[i];
//插入的值不断与之前进行判断,符合条件就插入并终止当次的循环,这个特点符合while函数
while((preindex>=0)&&(arr[preindex]>current)){
//后面的值用前面的替代
arr[preindex+1]=arr[preindex];
//每比较一次下标减一
preindex--;
}
//将要插入的值current存入arr[preindex+1]
arr[preindex+1]=current;
}
return arr;
}
}
4、希尔排序(Shell Sort)
a.动图演示:
b.算法描述:
希尔排序,又称缩小增量排序。先根据增量将其分组,再不断缩小增量直到1为止。在之前的分组中不断的应用插入排序。
c.代码实现:
class ShellSort{
public int[] Shellsort(int[] arr){
int increment=arr.length;
while (increment>1){
increment=increment/3+1;
for(int i=0;i<increment;i++){
for(int j=i+increment;j<arr.length;j=j+increment){
int preindex=j-increment;
int current=arr[j];
//插入的值不断与之前进行判断,符合条件就插入并终止当次的循环,这个特点符合while函数
//preindex>=0主要是为了判断while函数里面的preindex--之后是否符合要求,要先判断,否则报错。
//这个函数从左侧往右侧慢慢延伸
while((preindex>=0)&&(arr[preindex]>current)){
//如果前面的数比目标值大,后面的值用前面的替代
arr[preindex+increment]=arr[preindex];
//每比较一次下标减增量
preindex=preindex-increment;
}
//将要插入的值current存入arr[preindex+增量]
arr[preindex+increment]=current;
}
}
}
return arr;
}
}
5、归并排序(Merge Sort)
a.动图演示:
b.算法描述:
该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
该方法分为两部:
1.递归:先将序列不断分解
2:合并:将有序的子序列合并(该方法基于2路归并,2路归并一定是有序的子序列,所以第一步要不断细化到粒度为1的序列,因为粒度为1的序列是有序的!)
c.代码实现:
class MergeSort{
//递归将一个数组分成两个
public int[] Mergesort(int[] arr){
int[] left=null;
int[] right=null;
//如果数组长度小于2就不能再细分,就直接返回
if(arr.length<2){
return arr;
}
left=new int[arr.length/2];
right=new int[arr.length-arr.length/2];
for(int i=0;i<arr.length/2;i++){
left[i]=arr[i];
}
for(int j=0;j<arr.length-arr.length/2;j++){
right[j]=arr[j+arr.length/2];
}
//递归的精髓
return merge(Mergesort(left),Mergesort(right));
}
//合并将两个有序数组合并为一个有序数组
public int[] merge(int[] left,int[] right){
int[] temp=new int[left.length+right.length];
int index_left=0,index_right=0,index_temp=0;
//都是小于号,没有等号
while(index_left<left.length&&index_right<right.length){
if(left[index_left]>right[index_right]){
temp[index_temp++]=right[index_right++];
}
else{
temp[index_temp++]=left[index_left++];
}
}
while(index_left<left.length){
temp[index_temp++]=left[index_left++];
}
while(index_right<right.length){
temp[index_temp++]=right[index_right++];
}
return temp;
}
}
6、快速排序(Quick Sort)
a.动图演示:
b.算法描述:
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。
接着分别比较左右两边的序列,重复上述的循环。
c.代码实现:
public static void quickSort(int[] arr,int low,int high) {
int i=low;
int j=high;
int ref=arr[low];
while(i<j){
//从后往前比较
//如果从右往左查询到比参考点更小的就与参考点进行交换。while里面只要j--一句话!
while(i<j&&arr[j]>=ref)
j--;
if(arr[j]<=ref){
swap(arr,i,j);
}
//从前往后比较
while(i<j&&arr[i]<=ref)
i++;
if(arr[i]>=ref){
swap(arr,i,j);
}
}
//没有判断会堆栈溢出
if(i>low)
//左边序列。第一个索引位置到关键值索引-1
quickSort(arr,low,i-1);
//右边序列。从关键值索引+1到最后一个
if(j<high)
quickSort(arr,j+1,high);
}
public static void swap(int[] arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args){
int[] arr = {5,4,81,12,4,46,78,1,33,69};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]); }
}
线性时间非比较类排序尚未研究...