排序算法
1冒泡排序算法
1.1 原理
从序列的头部开始,依次比较相邻两个数的值,若逆序,则交换两个数的位置。一轮下来,尾部的数的位置可以确定为极值(若顺序为从小到大,即为最大值)。第二轮开始,最后一个数据则不用参与交换,第二轮可以确定除最后一个数外的极值(若顺序为从小到大,即为第二大的值)。依此类推,则可以进行n-1(n为序列的大小)轮排序后,序列为有序。
1.2 代码实现
//定义一个长度为80000的随机数组
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int) (Math.random() * 8000000);
}
//定义一个标志,用于判断是否进行了交换。若一轮中未进行交换,则代表此时序列已经有序,可以提前结束排序
boolean flag = false;
//定义一个暂时保存数值的对象
int temp = 0;
//外循环为冒泡排序轮次,共需进行n-1轮,故进行n-1次循环;因为每一轮需要判断交换的次数是递减的,故使用i自减的形式
for (int i = arr.length - 1; i > 0; i--) {
//内循环为每一轮的比较
for (int j = 0; j < i; j++) {
//判断是否需要交换(这里按从小到大排序)
if (arr[j] > arr[j + 1]) {
flag = true;//将是否进行交换的标志状态赋值为true
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
//如果未进行过交换,直接跳出循环
if (!flag) {
break;
} else {
flag = false;
}
}
2. 选择排序算法
2.1 原理
先从数组中找到符合顺序的数,然后按照规定交换位置
例如在一个长度为n的数组arr中,按照从小到大排序的步骤为:
- 第1次从arr[0]~arr[n-1]中找到最小的数,将其与arr[0]上的数交换位置;
- 第2次从arr[1]~arr[n-1]中找到最小的数,将其与arr[1]上的数交换位置;
… - 第n-1次从arr[n-2]~arr[n-1]中找到最小的数, 将其与arr[n-2]上的数交换位置.
2.2 代码实现
public static void main(String[] args) {
//总共进行n-1次交换,做n-1次循环
for (int i = 0; i < arr.length-1; i++) {
//定义目标位置的索引
int minIndex = i;
int min = arr[i];
//找到指定范围内要找的最小值
for (int j = i+1; j < arr.length; j++) {
if(min > arr[j]){
minIndex=j;
min=arr[j];
}
}
//判断是否需要进行交换
if(minIndex!=i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
3. 插入算法
3.1 原理
把n个元素看成一个有序表和一个无序表,有序表内只有一个元素,将无序表的元素依次按照规则插入到有序表中。
例如在长度为n的数组arr中,按照从小到大排序的步骤为:
- 第1步将arr[0]看为有序表,arr[1]~arr[n-1]为无序表,将arr[1]与arr[0]的数据进行比较,若逆序,则交换位置,可以将此步骤视为判断arr[1]的数据应当排在arr[0]上数据的前面还是后面;
- 第2步将arr[0]~arr[1]看为有序表,arr[2] ~arr[n-1]为无序表,将arr[2]与arr[1]的数据进行比较,若逆序,则交换位置,并且继续与arr[0]进行比较;
- 以此类推,第n-1步时进行最后一个数据的插入。
3.2 代码实现
public static void insertSort(int[] arr){
//共进行n-1次插入,故做n-1次循环
for (int i = 1; i < arr.length; i++) {
//定义插入值和插入目标(即要进行比较的目标)的索引
int insertVal = arr[i];
int insertIndex = i - 1;
//如果插入位置在插入目标前面,则要与下一个目标进行比较,直到全比较完或插入位置在目标后面
while (insertIndex >= 0 && insertVal<arr[insertIndex]){
arr[insertIndex+1]=arr[insertIndex];
insertIndex--;
}
arr[insertIndex+1]=insertVal;
}
}
4 希尔排序算法
4.1 原理
希尔排序是将插入排序改进后的更高效的一个版本,把元素按照一定增量分组,随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,进行最后一次排序。
4.2 代码实现
public static void shellSort(int[] arr){
int temp = 0;
int count = 0;
for (int gap = arr.length/2;gap>0;gap/=2){
for (int i = gap;i<arr.length;i++){
for(int j= i-gap;j>=0;j-=gap){
if(arr[j]>arr[j+gap]){
temp =arr[j];
arr[j]= arr[j+gap];
arr[j+gap]=temp;
}
}
}
}
}
public static void shellSort2(int[] arr){
for (int gap = arr.length/2;gap>0;gap/=2){
for (int i = gap; i < arr.length; i++) {
int j=i;
int temp=arr[j];
if(arr[j]<arr[j-gap]){
while (j-gap>=0&&temp<arr[j-gap]){
arr[j]=arr[j-gap];
j-=gap;
}
arr[j]=temp;
}
}
}
}
5 快速排序算法
5.1 原理
快速排序是对冒泡排序的一种改进。基本思路为:通过一趟排序将一组元素分为两部分,其中一部分元素比另一部分元素都小,
然后对这两部分都分别进行快速排序,整个排序过程可以递归进行,以此完成整个排序。
例:将一组元素中的中间元素为基准,把比它小的数放到左边,比它大的数放在右边,即可完成一次分组。
5.2 代码实现
public static void quickSort(int[] arr,int left,int right){
int l = left;
int r = right;
int pivot = arr[(left+right)/2];
int temp = 0;
while (1<r){
while (arr[l]<pivot){
l+=1;
}
while (arr[r]>pivot){
r-=1;
}
if(l>=r){
break;
}
temp = arr[l];
arr[l]=arr[r];
arr[r]=temp;
if(arr[l]==pivot){
r-=1;
}
if(arr[r]==pivot){
l+=1;
}
}
if(l==r){
l+=1;
r-=1;
}
if(left<r){
quickSort(arr, left,r);
}
if(right>l){
quickSort(arr, l,right);
}
}
6 归并排序算法
6.1 原理
归并排序是利用归并的思想实现的排序算法,采用经典的分治策略。先将问题分成小问题然后递归求解,治则是将各个小问题的解修补在一起。
例如:
分阶段:将8个元素分成2组,每组4个元素,再将4个元素分为2组,每组2个元素,再将2个元素分为2组,每组1一个元素。
治阶段:将分开的2组数合并成一组数,合并过程要排序。将8组元素合并成4组,合并4次,形成4组有序数组;将4组有序数组合并成2组,合并2次,形成2个有序数组;将2组元素合并成一组,合并一次,形成一个有序数组。
6.2 代码实现
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if(left<right){
int mid = (left+right)/2;
mergeSort(arr,left,mid,temp);
mergeSort(arr,mid+1,right,temp);
merge(arr,left,mid,right,temp);
}
}
public 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];
t+=1;
i+=1;
}else {
temp[t] = arr[j];
t+=1;
j+=1;
}
}
while (i<=mid){
temp[t] = arr[i];
t+=1;
i+=1;
}
while (j<=right){
temp[t] = arr[j];
t+=1;
j+=1;
}
t=0;
int tempLeft =left;
while (tempLeft<=right){
arr[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
7 基数排序算法
7.1 原理
建立10个桶,每个桶按顺序给定0~9十个下标。将要排序的数组按顺序放入桶内。
放入规则为:
第一轮以个位上的数为准,放入对应下标的桶内,全部放入后,按桶的下标顺序取出并放回数组(桶内的取出规则为先放的先取)
第二轮则以十位上的数为准,以此类推,即经过最大数的最高位的位数的轮次后,完成排序。
代码实现时,创建一个二位数组代表桶,创建一个一维数组代表桶内的指针。
7.2 代码实现
public static void radixSort(int[] arr){
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if(arr[i]>max){
max=arr[i];
}
}
int maxLength = (max+"").length();
int[][] bucket = new int[10][arr.length];
int[] bucketElementCounts = new int[10];
for (int i = 0,n=1; i < maxLength; i++,n*=10) {
for (int j = 0; j < arr.length; j++) {
int digitOfElement = arr[j]/n%10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
int index = 0;
for(int k=0;k<bucketElementCounts.length;k++){
if(bucketElementCounts[k]!=0){
for (int l = 0; l < bucketElementCounts[k]; l++) {
arr[index++] = bucket[k][l];
}
}
bucketElementCounts[k]=0;
}
}
}