本部分排序算法知识已托管于Github,详见 排序算法总结 | 欢迎各位star
冒泡排序算法通过多次比较和交换来实现排序,其排序流程如下:
1. 对数组中的各数据,依次比较相邻的两个元素的大小。
2. 如果前面的数据大于后面的数据,就交换这两个数据。经过第一轮的多次比较排序后,便可以将最小的数据排好。
3. 再用同样的方法把剩余的数据逐个进行比较,最后便可以按照从小到大的顺序排好数组各数据。
核心代码:
public void bubbleSort(int[] a,int n){
int i,j;
for(i=0; i1; i++){
boolean exchange = false;
for(j=n-1; j>i; j--){
if(a[j]1]){
int temp = a[j];
a[j]=a[j-1];
a[j-1]=temp;
exchange = true;
}
}
if(!exchange)
return;
}
}
完整示例代码:bubble.java
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
1. 首先设定一个分界值,通过该分界值来将数组分成两部分。
2. 将大于等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于等于分界值,而右边部分中各元素都大于等于分界值。
3. 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分为左右两部分,同样将左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
4. 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序,再递归排好右侧部分的顺序。当左、右两部分各数据排序完成后,整个数组的排序也就完成了。
核心代码:
public void quickSort(int[] a, int left, int right){ // 快速排序算法
int mid,t;
int rtemp,ltemp;
ltemp = left;
rtemp = right;
mid = a[(left+right)/2]; // 分界值
while(ltempwhile(a[ltemp]while(a[rtemp]>mid){
rtemp--;
}
if(ltemp<=rtemp){
t=a[ltemp];
a[ltemp]=a[rtemp];
a[rtemp]=t;
ltemp++;
rtemp--;
}
}
if(ltemp==rtemp){
ltemp++;
}
if(left1); // 左递归调用
}
if(ltemp1, right); // 右递归调用
}
}
程序中首先确定分解值为数组中间位置的值,当然也可以选在其他位置,比如数组的第一个数据。然后按照快速排序法的思路进行处理。接着,通过递归调用,处理分界值左侧的元素和右侧的元素。
完整示例代码:quick.java
选择排序算法通过选择和交换来实现排序,其排序流程如下:
1. 首先从原始数组中选择最小的1个数据,将其和位于第1个位置的数据交换。
2. 接着从剩下的n-1个数据中选择次小的1个数据,将其和第2个位置的数据交换。
3. 然后不断重复上述过程,直到最后两个数据完成交换。至此,便完成了对原始数组的从小到大的排序。
核心代码:
public void bubbleSort(int[] a,int n){
int i,j;
int index;
for(i=0; i1; i++){
index = i;
for(j=i+1; jif(a[index]>a[j]){
index = j;
}
}
if(index != i){
int temp = a[index];
a[index]=a[i];
a[i]=temp;
}
}
}
完整示例代码:select.java
堆排序(Heap Sort)算法是基于选择排序思想的算法,其利用堆结构和二叉树的一些性质来完成数据的排序。堆结构是一种树结构,准确的说是一个完全二叉树。在这个树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件:
○ 如果按照从小到大的顺序排序,要求非叶结点的数据要大于或等于其左、右子结点的数据。
○ 如果按照从大到小的顺序排列,要求非叶结点的数据要小于或等于其左、右子结点的数据。
堆排序过程
一个完整的堆排序需要经过反复的两个步骤:构造堆结构和堆排序输出。下面首先分析如何构造堆结构。
构造堆结构就是把原始的无序数据按前面堆结构的定义进行调整。首先,需要将原始的无序数据放置到一个完全二叉树的各个结点中。
然后由完全二叉树的下层向上层逐层对父结点的数据进行比较,使父结点的数据大于子结点的数据,这里需要使用“筛”运算进行节点数据的调整,直到所有结点最后满足堆结构的条件为止。在执行筛运算时,值较小的数据将逐层下移。
插入排序算法通过比较和插入来实现排序,其排序流程如下:
1. 首先对数组的前两个数据进行从小到大的排序。
2. 接着将第3个数据与排好序的两个数据比较,将第3个数据插入合适的位置。
3. 然后,将第4个数据插入已排好序的前3个数据中。
4. 不断重复上述过程,直到把最后一个数据插入合适的位置。最后,便完成了对原始数组从小到大的排序。
核心代码:
public void bubbleSort(int[] a,int n){
int i,j;
int t;
for(i=1; i1;
while(j>=0 && t// 后移每个比t大的元素
a[j+1]=a[j];
j--;
}
a[j+1]=t; // 将腾出来的那个位置插入新元素
}
}
插入排序时,如果元数据已经基本有序,则排序的效率就可大大提高。另外,对于数量较小的序列使用直接插入排序,因需要移动的数据量较小,其效率也较高。
完整示例代码:insert.java
折半插入算法是在插入排序算法的基础上,在已排序序列中选择插入位置时,优化使用二分查找方法,使得排序效率提升。
核心代码:
public static void BinaryInsertSort(int[] a) {
int low, high;
int mid, temp;
for (int i = 0; i < a.length; i++) {
temp = a[i];
low = 0;
high = i - 1;
while (low <= high) { // 折半查找的过程
mid = (low + high) / 2;
if (temp < a[mid])
high = mid - 1;
else
low = mid + 1;
}
for (int j = i - 1; j > high; j--)
a[j + 1] = a[j];
a[high + 1] = temp;
}
}
完整示例代码:binaryInsert.java
Shell排序算法严格来说基于插入排序的思想,其又称为希尔排序或者缩小增量排序。Shell排序算法的排序流程如下:
1. 将有n个元素的数组分为n/2个数字序列,第1个数据和第n/2+1个数据为一对,第2个数据和第n/2+2个数据为一对,……
2. 一次循环使每一个序列对排好序
3. 然后,再变为n/4个序列,再次排序。
4. 不断重复上述过程,随着序列减少最后变为一个,也就完成了整个序列。
核心代码:
public void bubbleSort(int[] a,int n){
int i,j,r;
int t;
for(r=n/2;r>=1;r/=2){ // 设置间距r 分组比较
for(i=r; iwhile(j>=0 && t// 后移每个比t大的元素
a[j+r]=a[j];
j-=r;
}
a[j+r]=t; // 将腾出来的那个位置插入新元素
}
}
}
在程序中使用了三重循环嵌套。最外层的循环用来分解数组元素为多个序列,每次比较两数的间距,直到其值为0就结束循环。下面一层循环按设置的间距r,分别比较对应的数组元素。在该循环中使用插入排序法对指定间距的元素进行排序。
完整示例代码:shell.java
归并排序(Merge Sort)算法就是将多个有序数据表归并成一个有序数据表。如果参与归并的只有两个有序表,则称为二路归并。对于一个原始的待排序序列,往往可以通过分割的方法来归结为多路归并排序。
一个待排序的原始数据序列进行归并排序的基本思路是,首先将含有n个结点的待排序数据序列看作由n个长度为1的有序子表组成,将其依次两两归并,得到长度为4的若干有序子表······,重复上述过程,一直到最后的子表长度为n,从而完成排序过程。
● 冒泡排序算法:冒泡排序中,存在二层循环遍历,所以平均时间复杂度为O(n²),最坏情况下的时间复杂度为O(n²);
● 快速排序算法:快序中,while循环部分时间复杂度为O(logn),左递归和右递归总和的时间复杂度为O(n),所以总的平均时间复杂度为O(n²);
● 选择排序算法:选择排序中,依次从数组中选取最小的,次小的,… 从而得到整个序列。两层循环遍历,所以时间复杂度为O(n²),最坏情况下的时间复杂度为O(n²);
● 堆排序算法:从堆中,一次堆排序挑选最小(或最大)元素的时间复杂度为O(logn),一共要进行n次堆排序得到有序队列,所以平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(nlogn);
● 插入排序算法:插入排序中,两层循环,第一层遍历n个元素,第二层遍历在已排序队列中逐一向前比较,找到合适的位置插入,所以平均时间复杂度为O(n²),最坏情况下的时间复杂度为O(n²);
● 折半插入排序算法:在插入排序的基础上进行优化,在第二层遍历在已排序队列中通过二分查找的方式,找到合适的位置插入,所以平均时间复杂度为O(n²),最坏情况下的时间复杂度为O(n²);
● Shell排序算法:在插入排序的基础上进行优化,通过先将队列进行n/2,n/4,n/8,…分组,时间复杂度为O(n½),再对每个小组分别进行插入排序,时间复杂度为O(n),所以平均时间复杂度将会缩减为O(n³/₂),最坏最坏情况下的时间复杂度为O(n²);:
● 归并排序算法:平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(nlogn);