目录
1.冒泡排序
把数组上下放置,每次将最下面的数依次向上比较,较大数向上移动,第一轮过后,最大的数放在了最顶部,第二轮过后次大的数放在次顶部.. 直到数组拍好序。过程就像水中的泡泡向上走一样,所以称之为“冒泡排序”;下面为核心代码
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] >= arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
下面给出完整代码
public class BubblingSort {
public static void main(String[] args) {
int[] arr = {8,6,67,5,2,3,45,2354,45};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr){
boolean flag = false;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] >= arr[j+1]){
flag = true;
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
if (flag){
flag = false;
}else{
System.out.println("在进行到第" + (i+1) + "次排序时 退出!因为已经排序完成!");
break;
}
}
}
}
2.选择排序
选择排序与冒泡排序有点类似,选择排序思路为:
第一次排序:
找到数组中最小的数,将这个数与数组第一个位置交换
第二次排序:
从第二个位置开始,找到数组中最小的数,将这个数与数组第2个位置交换
第三次排序:
从第三个位置开始,找到数组中最小的数,将这个数与数组中第3个位置交换
...
核心代码
for (int i = 0; i < arr.length - 1; i++) {
int min = arr[i]; //保存最小的数
int index = i; //存最小数的下标
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
index = j;
min = arr[j];
}
}
//交换位置
if (index != i) {
arr[index] = arr[i];
arr[i] = min;
}
}
完整代码
public class SelectingSort {
public static void main(String[] args) {
int[] arr = {8, 6, 67, 5, 2, 3, 45, 2354, 45};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int min = arr[i];
int index = i;
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
index = j;
min = arr[j];
}
}
//交换位置
if (index != i) {
arr[index] = arr[i];
arr[i] = min;
}
}
}
}
3.插入排序
插入排序将数组看作一个有序数组和一个无序数组,每次将无序数组的第一个数,插入到有序数组中。思路为:
将第一个数看作是有序数组,剩下的为无序数组
1.把无序数组第一个数与有序数组的数比较,然后插入到合适的位置,形成新的有序数组,和新的无序数组
2.把无序数组第一个数与有序数组的数比较,然后插入到合适的位置,形成新的有序数组,和新的无序数组
3...
核心代码
for (int i = 1; i < arr.length; i++) {
int sor = arr[i]; //无序数组的第一个数
int sorIndex = i -1; //有序数组的最后一个数的下标
//寻找合适的位置
while ( sorIndex >= 0 && sor < arr[sorIndex]){
//当sor从后向前依次与有序数组的数相比,当sor小时,将有序数组的数向后移动一格
//后移
arr[sorIndex+1]=arr[sorIndex];
sorIndex --;
}
//已经找到合适的位置,为sorIndex +1 ;插入进行插入
arr[sorIndex+1] = sor;
System.out.println( "第"+i+"次排序结果为:" +Arrays.toString(arr));
}
完整代码
public class InsertionSort {
public static void main(String[] args) {
int[] arr = {6,5,2,3,84,32,45};
sort(arr);
}
public static void sort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int sor = arr[i]; //无序数组的第一个数
int sorIndex = i -1; //有序数组的最后一个数的下标
//寻找合适的位置
while ( sorIndex >= 0 && sor < arr[sorIndex]){
//当sor从后向前依次与有序数组的数相比,当sor小时,将有序数组的数向后移动一格
//后移
arr[sorIndex+1]=arr[sorIndex];
sorIndex --;
}
//已经找到合适的位置,为sorIndex +1 ;插入进行插入
arr[sorIndex+1] = sor;
System.out.println( "第"+i+"次排序结果为:" +Arrays.toString(arr));
}
}
}
4.希尔排序
希尔排序时希尔(Donald Shell)提出的一种算法。希尔排序也是一种插入排序,它是简单插入排序的经过改进之后的一种更高效的版本,也被称为缩小增量排序
希尔排序基本思想:
希尔排序是把数组(记录)按下标的一定增量进行分组,对每组使用直接排序算法排序;随着增量的减小,每组包含的关键词越来越多,当增量减小到1时,整个文件恰被分成一组,算法终止;
思路:
1.将数组(记录)长度的2分之一作为增量,分为(增量)个组:对每组使用希尔排序
2.将增量的2分之一作为新的增量,分为(增量)个组,对每组使用希尔排序
3将增量的2分之一作为新的增量,分为(增量)个组,对每组使用希尔排序
4...
核心代码
for (int gap = arr.length / 2; gap > 0 ; gap /= 2){
for (int i = gap; i < arr.length; i++) {
// 遍历各组中所有的元素(共gap组,每组有arr.length/gap个元素),步长gap
//这里使用移动法Sell排序
int sorIndex = i;
int sor = arr[i];
//寻找合适的位置
while(sorIndex - gap >= 0 && sor < arr[sorIndex - gap]){
//后移
arr[sorIndex] = arr[sorIndex - gap];
sorIndex -= gap;
}
arr[sorIndex] = sor;
}
//System.out.println("第"+(++count)+"次希尔排序后的结果为:" + Arrays.toString(arr));
}
完整代码
public class ShellSort {
public static void main(String[] args) {
int[] arr = {1,5,436,7,6,78,45,9};
sort(arr);
System.out.println(Arrays.toString(arr));
}
public static void sort(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++) {
// 遍历各组中所有的元素(共gap组,每组有arr.length/gap个元素),步长gap
//这里使用移动法Sell排序
int sorIndex = i;
int sor = arr[i];
//寻找合适的位置
while(sorIndex - gap >= 0 && sor < arr[sorIndex - gap]){
//后移
arr[sorIndex] = arr[sorIndex - gap];
sorIndex -= gap;
}
arr[sorIndex] = sor;
}
//System.out.println("第"+(++count)+"次希尔排序后的结果为:" + Arrays.toString(arr));
}
}
}
5.快速排序
例:将记录的最后一条作为参考,把比它小的数放左边,比它大的数放右边,分成两组,每个组重复此操作
核心代码
public static void sort(int[] arr ,int star ,int end){
//1.以最后一位数字为基准,将数组分割为两边的数
int base = arr[end-1];
int baseIn = end-1;
int temp = 0 ;//临时变量用来交换
for (int i = end - 2 ; i >= star; i--) {
if (arr[i] > base){
//放右边
//从i开始到baseIn 使用移动法,把它移动到base右边
temp = arr[i];
int t_1 = i;
while ( t_1 < baseIn){
arr[t_1] = arr[t_1 + 1];
t_1++;
}
arr[baseIn] = temp;
baseIn --;
}
}
if (baseIn - star > 1){//当前面还有数组要排序时
sort(arr,star,baseIn);
}
if ( (end - 1 - baseIn) > 1){//当后面还有数组要排序时
sort(arr, baseIn, end);
}
}
还有一种是韩老师课堂上的,以记录中位数为参考数,将左边校参考数大数与右边较小数交换
public static void quickSort(int[] arr,int left,int right){
int l = left;//左下标
int r = right;//右下标
//pivot:中轴值
int pivot = arr[ (left + right ) /2];
int temp = 0 ;//临时变量,作为交换时使用
//while循环的目的是让比pivot 值小的放左边
while (l < r){
//再pivot的左边一直找,找到大于等于pivot的值才退出
while ( arr[l] < pivot){
l ++;
}
//在pivot的右边一直找,找到小于等于pivot的值才退出
while ( arr[r] > pivot){
r --;
}
//如果 l >= r 说明pivot左右两边的值,已经按照左边全都是小于等于pivot,右边全是大于等于pivot
if ( l >= r){
break;
}
//交换
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//如果交换完后,发现这个arr[l] == pivot 值,就 l-- ,前移
if (arr[l] == pivot){
r--;
}
//如果交换完后,发现这个arr[r] == pivot 值,就 r++ ,后移
if (arr[r] == pivot){
l++;
}
}
if (l==r){
l += 1;
r -= 1;
}
//向左递归
if (left < r){
quickSort(arr,left,r);
}
if (right > l){
quickSort(arr,l,right);
}
}
以第一个数为基准
public void QuickSort(int arr[], int start, int end)
{
if (start >= end)
return;
int i = start;
int j = end;
// 基准数
int baseval = arr[start];
while (i < j)
{
// 从右向左找比基准数小的数
while (i < j && arr[j] >= baseval)
{
j--;
}
if (i < j)
{
arr[i] = arr[j];
i++;
}
// 从左向右找比基准数大的数
while (i < j && arr[i] < baseval)
{
i++;
}
if (i < j)
{
arr[j] = arr[i];
j--;
}
}
// 把基准数放到i的位置
arr[i] = baseval;
// 递归
QuickSort(arr, start, i - 1);
QuickSort(arr, i + 1, end);
}
6.归并排序
归并排序是利用递归的思想实现的排序方法,该算法利用经典的分治策略(分治法将问题分解成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各个答案“缝补”在一起,即分而治之)
完整代码
public class MergetSort {
public static void main(String[] args) {
int[] arr = {8,4,5,7,1,3,6,2};
int[] temp = new int[arr.length];
mergeSort(arr,0, arr.length-1,temp);
System.out.println(Arrays.toString(arr));
}
public static void mergeSort(int[] arr,int left, int right,int[] temp){
if (left < right){
int mid = (left + right) /2;
System.out.println("left: " + left + " ;right: " + right);
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
merge(arr,left,mid,right,temp);
}
}
/**
* 合并数组
* @param arr 原始数组
* @param left 左数左下标
* @param mid 中间位置
* @param right 右数下标
* @param temp 临时数组
*/
public static void merge(int[] arr,int left,int mid, int right,int[] temp){
int i = left; // 初始化i,左边有序序列的初始索引
int j = mid + 1; //初始化j,右边有序序列的初始索引
int t = 0; // 指向temp数组的当前索引
//1.先把左右两边的数据(都是有序的)按照规则拷贝到temp数组
while (i <= mid && j <= right){//当有一边的数据没有填充完
if (arr[i] <= arr[j]){
//左边跟右边的比较,发现左边的更小,把小的拷贝到temp
temp[t] = arr[i];
i++;
}else {
temp[t] = arr[j];
j++;
}
t++;
}
//2.把有剩余数据的一边的数据一次全部填充到temp
while (i <= mid){//左边的数组还没填充完
temp[t] = arr[i];
i++;
t++;
}
while (j <= right){
temp[t] = arr[j];
j++;
t++;
}
//3.将temp数据的元素拷贝到arr[]数组中
//注意,并不是每次都拷贝所有
t = 0 ;
int tempLeft = left;
while (tempLeft <= right){
arr[tempLeft] = temp[t];
tempLeft++;
t++;
}
}
}
7.基数排序
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
第一步
以LSD为例,假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39
第二步
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93
第三步
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
完整代码
public class RadixSort {
public static void main(String[] args) {
int arr[] = {53,3,542,748,14,214};
readisSort(arr);
}
//基数排序方法
public static void readisSort(int[] arr){
//第一轮(针对每个元素的个位数进行排序)
//定义一个二位数组,表示10个通,每个桶就是一个二维数组
//2.为了防止数组越界,我们只能将长度定为arr.length
//3.很明显,桶排序是一个用空间换时间的排序方法
int[][] bucket = new int[10][arr.length];
//为了记录每个桶中实际存放的多少个数据,我们定义一个一维数组,
//bucketElementCounts[1] 就是bucket[1]里面的存放个数
int[] bucketElementCounts = new int[10];
//为了知道排序的次数,我们需要得到记录的最大数
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max){
max = arr[i];
}
}
//int maxLength = (max + "").length();
int maxLength = (int)Math.log10(max) + 1;
int index;
for (int i = 0; i < maxLength; i++) {
for (int j = 0; j < arr.length; j++) {
//取出每个元素的个位
int digitOfElement = arr[j] / (int)Math.pow(10,i) % 10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]++] = arr[j];
}
//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数据)
index = 0 ;
for (int k = 0; k < bucket.length; k++) {
if (bucketElementCounts[k]!=0){
for (int l = 0; l < bucketElementCounts[k]; l++) {
arr[index++] = bucket[k][l];
}
}
//将记录桶存放的数归零
bucketElementCounts[k] = 0;
}
System.out.println("第"+(i+1)+"轮处理"+Arrays.toString(arr));
}
}
}