1.选择排序
原理:
第一次循环将数组的第一个数与第二个数比较,如果第一个数比第二个数大,就将他们互换位置,然后按照这种方式依次将第一个数和第三个、第四个数.......进行比较;
第二次循环从数组的第二个值开始,执行方式和第一次一样
这样一直到第n-1次
其实第一次循环完,数组中最小的一个值为数组中第一个数,
第二次循环完,数组中第二小的数处于数组中第二个位置,
经过n-1次循环,前面n-1个数都是有序的且小于最后一个值,这样整个数组就是有序的。
也可以这样理解,首先将数组中最小的数找出来放在数组中第一个位置上,然后找出arr[1]~arr[arr.length-1]这个新数组中最小值放在新数组中第一个位置上,依次循环下去,直到形成的新数组只剩下一个数,排序也就完成了
代码实现如下:
import java.util.Arrays;
public class SortDemo{
public static void main(String[] args){
int[] arr = new int[]{3, 43,22,56,12,54,98,1,45};
selectionSort(arr);
System.out.println(Arrays.toString(arr));
}
static void selectionSort(int[] arr){
for(int i=0; i<arr.length-1; i++){
for(int j=i+1; j<arr.length; j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
}
2.冒泡排序
原理:
选择排序是每次将最小的数提到数组头部,而冒泡排序则是每次将将最小的数沉到数组尾部。
第一轮排序是将第一个数和第二个数进行比较,如果第一个数大于第二个数就互换位置,然后第二个数和第三个数比较如果第二个数大也互换位置,这样一直到数组末尾。第一轮排序完数组中最大的那个数也就到了末尾。
第二轮排序时和第一轮排序一样,只是我们不会考虑已经沉到末尾的数。
这样进行n-1轮排序,数组也就是有序的了。
代码实现如下:
static void bubbleSort(int[] arr){
for(int i=0; i<arr.length-1; i++){
for(int j=0; j<arr.length-1-i; j++){
if(arr[j]>arr[j+1])
swap(arr, j, j+1);
}
}
}
static void swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
3.插入排序
原理:
你可以想象自己手里有一副扑克牌,现在你手里的牌是从左到右有序排列的,你抓取一张新的牌要将它插进去,并且形成的新的牌也必须有序。这时我们可以从最右边开始依次和右边的牌进行比较,找到第一张比它小的牌,将这张牌插到它后面。
插入排序的原理就是这样的,取数组中的第一个数放入新数组中第一个位置,然后取数组中第二个数,将从新数组实际长度的右边开始依次和这些数进行比较找到第一个比它小的数,将这个数后面的所有数后移一位,将取出来的数放到空出来的位置。按照这种方式取第三个第四个......一直到最后一个。
代码实现:
static void insertSort(int[] arr){
int[] newArr = new int[arr.length];
newArr[0] = arr[0];
int count = 1;
for(int i=1; i<arr.length; i++){
int temp = arr[i];
int j = count-1;
while(j>=0 && newArr[j]>temp)
j--;
for(int k=count-1; k>j; k--)
newArr[k+1] = newArr[k];
newArr[j+1] = temp;
count++;
}
for(int i=0; i<arr.length; i++){
arr[i] = newArr[i];
}
}
插入排序有一个改进的做法,我们都知道在有序数组中进行查找时,折半查找的效率是最高的,那么插入排序算法中查找部分可以改用二分查找的方式。
代码实现如下:
static void insertSort(int[] arr){
int[] newArr = new int[arr.length];
newArr[0] = arr[0];
int count = 1;
for(int i=1; i<arr.length; i++){
int temp = arr[i];
int j = searchBinary(newArr, 0, count-1, temp);
System.out.println(j);
for(int k=count-1; k>=j; k--)
newArr[k+1] = newArr[k];
newArr[j] = temp;
count++;
System.out.println(j+","+Arrays.toString(newArr));
}
for(int i=0; i<arr.length; i++){
arr[i] = newArr[i];
}
}
static int searchBinary(int[] arr, int s, int z, int target){
int i=s, j=z;
int mid;
while(i<=j){
mid = (j+i)/2;
if(arr[mid]>target)
j = mid-1;
else if(arr[mid]<target)
i = mid+1;
}
return i;
}
4.归并排序
原理:
归并排序用的是分化的思想,将两个有序的数组合并成一个有序的数组。为了得到有序的数组,一直对数组进行划分,这里我们通常采用一分为二的思想,直到得到的新数组中只有一个数时,这个数组就是有序的,然后将这个有序数组和另一个有序数组合并成一个有序的数组。那么原来那个划分成这两个数组的父数组也就是有序的。就这样层层向上,最后得到两个有序的数组,再将这两个有序的数组进行合并,就是原来那个数组了。并且现在是有序的了。
代码实现:
static void mergeSort(int[] arr, int s, int z){
int mid;
if(s<z){
mid = (z+s)/2;
mergeSort(arr, s, mid);
mergeSort(arr, mid+1, z);
merge(arr, s, mid, z);
}
}
//归并数组
static void merge(int[] arr, int s, int mid, int z){
int i=s, j=mid+1;
int[] temp = new int[z-s+1];
int count = 0;
for(; i<=mid && j<=z; ){
if(arr[i]<arr[j])
temp[count++] = arr[i++];
else
temp[count++] = arr[j++];
}
while(i<=mid)
temp[count++] = arr[i++];
while(j<=z)
temp[count++] = arr[j++];
for(i=0; i<count; i++){
arr[s+i] = temp[i];
}
}
5.快速排序
原理:
有人说一个萝卜一个坑。我是这样理解的,取出要排序数组中的第一个数,找到一个位置将这个数放在这里,这个位置满足他前面的数都比他小,后面的数都比他大。此时这个数在排序后所应处的位置就是这个位置了,他已经是有序的了。然后将这个位置前面的数和后面的数分别形成新的数组,用同样的方式进行下去直到新的数组中只有一个数,那么整个数组就是有序的了。如果你还有疑惑,试想一下,一个数前面的数比他小,后面的数比他大,前面只有一个数,后面也只有一个数,那么这三个数不是有序的么?
怎样为数组中第一个数找到那个位置呢?
我们是这样做的,将数组中的第一个数用一个变量存储起来,定义两个标志l、r,一个赋值为0,另一个arr.length-1,从数组尾部开始比较,找到第一个比他小的数,将这个数赋值给arr[l]。然后从头部开始比较找到第一个比他大的数,将他的值赋给arr[r]。继续循环比较直到l=z时停止,l或者说z的位置就是我们要找的位置,然后将原来的值赋给arr[l]。
代码实现:
static void quickSort(int[] arr, int s, int z){
int l = s, r = z;
int temp = arr[s];
while(l<r){
while(l<r && arr[r]>=temp)
r--;
arr[l] = arr[r];
while(l<r && arr[l]<=temp)
l++;
arr[r] = arr[l];
}
arr[l] = temp;
if(l-1>s)
quickSort(arr, s, l-1);
if(l+1<z)
quickSort(arr, l+1,z);
}