接前文七大搜索算法,这次对排序算法进行总结。
复杂度
1.冒泡排序
相邻两元素比较并交换位置,走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
Java实现
public class BubbleSort {
public static int[] Sort(int[] l){
int temp;
for(int i=0;i<l.length-1;i++){
for (int j=0;j<l.length-1-i;j++){
if(l[j]>l[j+1]){
temp=l[j];
l[j]=l[j+1];
l[j+1]=temp;
}
}
}
return l;
}
public static void main(String[] args) {
int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
int[] sort = BubbleSort.Sort(l);
for (int i :
sort) {
System.out.println(i);
}
}
}
2.选择排序
每次从未排序的元素中选出最值,放到已排序元素的末尾。
Java实现
public class SelectionSort {
public static int[] Sort(int[ ] l){
int temp;
int index ;
for(int i=0;i<l.length-1;i++){
index=i;
for(int j=i+1;j<l.length;j++){
if(l[index]>l[j]){
index=j;
}
}
temp=l[i];
l[i]=l[index];
l[index]=temp;
}
return l;
}
public static void main(String[] args) {
int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
int[] sort = SelectionSort.Sort(l);
for (int i :
sort) {
System.out.println(i);
}
}
}
3.插入排序
插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。
Java实现
public class InsertionSort {
public static int[] Sort(int[] l){
for(int i=0;i< l.length-1;i++){
int temp=l[i+1];
int j=i+1;
while (j>0&&temp<l[j-1]){
l[j]=l[j-1];
j--;
}
l[j]=temp;
}
return l;
}
public static void main(String[] args) {
int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
int[] sort = InsertionSort.Sort(l);
for (int i :
sort) {
System.out.println(i);
}
}
}
4.希尔排序
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
Java实现
public class ShellSort {
public static int[] Sort(int [] l){
int step=l.length/2;
while (step >= 1){
for (int i = step; i < l.length; i++) {
int val = l[i];
int j = i - step;
for (; j >= 0; j -= step){
if (l[j] > val){
l[j + step] = l[j];
}
else {
break;
}
}
l[j + step] = val;
}
step = step / 2;
}
return l;
}
public static void main(String[] args) {
int[] l = new int[]{4654, 47864, 1565, 7132, 3, 5, 7, 6};
int[] sort = ShellSort.Sort(l);
for (int i :
sort) {
System.out.println(i);
}
}
}
5.归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
Java实现
public class MergeSort {
public static int[] Sort(int[] arr){
int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
sort(arr,0,arr.length-1,temp);
return arr;
}
private static void sort(int[] arr,int left,int right,int []temp){
if(left<right){
int mid = (left+right)/2;
sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
}
}
private static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//左序列指针
int j = mid+1;//右序列指针
int t = 0;//临时数组指针
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t++] = arr[i++];
}else {
temp[t++] = arr[j++];
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while(left <= right){
arr[left++] = temp[t++];
}
}
public static void main(String[] args) {
int[] l = new int[]{4654, 47864, 1565, 7132, 3, 5, 7, 6};
int[] sort = MergeSort.Sort(l);
for (int i :
sort) {
System.out.println(i);
}
}
}
6.快速排序
基本思想
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。
(3)然后,左边和右边的数据可以独立排序。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。
public class QuickSort {
public static int[] Sort(int arr[],int start,int end) {
int pivot = arr[start];
int i = start;
int j = end;
while (i<j) {
while ((i<j)&&(arr[j]>pivot)) {
j--;
}
while ((i<j)&&(arr[i]<pivot)) {
i++;
}
if ((arr[i]==arr[j])&&(i<j)) { //这个判断是为了防止重复元素陷入死循环
i++;
} else {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
if (i-1>start) arr=Sort(arr,start,i-1);
if (j+1<end) arr=Sort(arr,j+1,end);
return (arr);
}
public static void main(String[] args) {
int[] l = new int[]{4654, 6, 1565, 7132, 3, 5, 7, 6};
int[] sort = QuickSort.Sort(l,0,7);
for (int i :
sort) {
System.out.println(i);
}
}
}
7.堆排序
基本思想
(1)将无序数组建为最大堆
(2)将堆顶元素与最后一个元素交换
(3)将堆大小减一,并使剩余元素仍构成最大堆
(4)重复以上操作
Java实现
public class HeapSort {
private static void heapify(int[] l,int n,int i){
int largest=i;
int lson=i*2+1;
int rson=i*2+2;
if(lson<n&&l[lson]>l[largest]){
largest=lson;
}
if(rson<n&&l[rson]>l[largest]){
largest=rson;
}
if(largest!=i){
int temp;
temp=l[largest];
l[largest]=l[i];
l[i]=temp;
heapify(l,n,largest);
}
}
private static void Sort(int[] l,int n){
//建堆
for (int i = n/2-1; i >=0 ; i--) {
heapify(l,10,i);
}
//排序
for (int i = n-1; i >0 ; i--) {
int temp;
temp=l[i];
l[i]=l[0];
l[0]=temp;
heapify(l,i,0);
}
}
public static void main(String[] args) {
int[] l={2,3,8,1,4,9,10,7,16,14};
Sort(l,10);
for (int i : l) {
System.out.println(i);
}
}
}
8.计数排序
基本思想
(1)找出待排序的数组中最大和最小的元素
(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项
(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
Java实现
public class CountingSort {
public static int[] Sort(int[] l){
int min=l[0];
int max=l[0];
for (int i = 1; i < l.length; i++) {
if(min>l[i]){
min=l[i];
}
if(max<l[i]){
max=l[i];
}
}
int K=max-min+1;
int[] Aux=new int[K];
for (int i = 0; i < K; i++) {
Aux[i]=0;
}
for (int i = 0; i < l.length; i++) {
Aux[l[i]-min]++;
}
int i=0;
for (int j = 0; j < K; j++) {
while(Aux[j]>0){
l[i++]=min;
Aux[j]--;
}
min++;
}
return l;
}
public static void main(String[] args) {
int[] l={2,3,8,1,4,9,10,7,16,14};
Sort(l);
for (int i : l) {
System.out.println(i);
}
}
}
9.基数排序
基本思想
直接看图很好理解。基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。
Java实现
public class RadixSort {
public static int[] Sort(int[] l){
int max=l[0];
for (int i = 0; i < l.length; i++) {
if(max<l[i]){
max=l[i];
}
}
for (int i=1; max/i>0 ;i*=10) {
int[] count=new int[10];
int[] templ=new int[l.length];
for (int j = 0; j < l.length; j++) {
int num=(l[j]/i)%10;
count[num]++;
}
for (int j = 1; j < 10; j++) {
count[j]+=count[j-1];
}
for (int j = l.length-1; j >=0 ; j--) {
templ[count[(l[j]/i)%10]-1]=l[j];
count[(l[j]/i)%10]--;
}
System.arraycopy(templ, 0, l, 0, l.length);
}
return l;
}
public static void main(String[] args) {
int[] l=new int[]{4654,47864,1565,7132,3,5,7,6};
Sort(l);
System.out.println(Arrays.toString(l));
}
}
10.桶排序
基本思想
实际上计数和基数排序都是运用了桶排序的思想。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:
(1)在额外空间充足的情况下,尽量增大桶的数量
(2)使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。