交换排序
冒泡排序
基本思想:通过对待排序序列从前向后,依次比较相邻元素的值,若发现逆序则交换
第一次优化:排序过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行交换,就说明序列有序
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {3,9,-1,10,-2};
//·过程 从小到大
int temp = 0;
//·优化:定义一个标识变量,
boolean flag = false;
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]) {
//·进行了交换 设置flag=true
flag=true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
System.out.print("第" + (i + 1) + "趟" + "第" + (j + 1) + "次结果");
System.out.print(Arrays.toString(arr));
System.out.println();
}
System.out.print("第"+ (i + 1) +"趟最终:");
System.out.print(Arrays.toString(arr));
System.out.println();
if(!flag) {//·没有进行交换 说明已经有序
break;
}else {
flag = false;//·重置flag
}
}
System.out.println(Arrays.toString(arr));
}
}
第二次优化:利用一个标志位,记录一下当前第 i 趟所交换的最后一个位置的下标,在进行第 i+1 趟的时候,只需要内循环到这个下标的位置就可以了,因为后面位置上的元素在上一趟中没有换位,这一次也不可能会换位置了
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {6,4,7,5,1,3,2};
//·过程 从小到大
int temp = 0;
//·优化:定义一个标识变量,
boolean flag = false;
//·记录最后依次交换的位置
int tempPosition = 0;
int len = arr.length-1;
for(int i = 0;i < arr.length-1 ; i++) {
for(int j = 0;j < len ;j++) {//·循环到最后一次交换的位置就行
if(arr[j]<arr[j+1]) {
//·进行了交换 设置flag=true
flag=true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
tempPosition = j;
}
System.out.print("第" + (i + 1) + "趟" + "第" + (j + 1) + "次结果");
System.out.print(Arrays.toString(arr));
System.out.println();
}
len = tempPosition;
System.out.print("第"+ (i + 1) +"趟最终:");
System.out.print(Arrays.toString(arr));
System.out.println();
if(!flag) {//·没有进行交换 说明已经有序
break;
}else {
flag = false;//·重置flag
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序
基本思想:快速排序是对冒泡排序的一种改进,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据段都比另外一部分的所有数据都小,然后再按此方法对这两部分分别进行快速排序,整个排序过程可以递归进行。
推荐查看添加链接描述
public class QuickSort {
public static void main(String[] args) {
int[] arr = {-9,78,0,23,-567,70,11,23,36524,123,56,-123,-23};
quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int l ,int r) {
if(l < r) {
int i = l;
int j = r;
int x = arr[i];
while(i < j) {
//从右向左找到小于x 的数来填充arr[i]
while(i < j && arr[j]>=x) {
//找到 j-1
j--;
}
//·循环结束后找到值把找到的这个数填充道a[i],先判断j-1后i j是否相等
if(i < j) {
arr[i] = arr[j];
i++;
}
//·从左向右找到大于x的数填充道arr[j]
while(i< j && arr[i] < x) {
i++;
}
if(i < j) {
arr[j] = arr[i];
j--;
}
}
//·循环结束后 i的位置就是x在序列中的最终位置
arr[i]= x;
quickSort(arr, l, i-1);
quickSort(arr, i+1, r);
}
}
}
选择排序
直接选择排序
基本思想:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
/**
* 1.选择排序一共有数组大小-1轮排序
* 2.每一个排序又是一个循环,规则如下
* 2.1先假定当前的数是最小的
* 2.2然后和后面的数比较,如果发现有比当前数小(大),就重新确定最小数,并得到下标
* 2.3当遍历完时,得到本轮最小数和下标
* 2.4交换
* @author DC
*
*/
public class SimpleSelectionSort {
public static void main(String[] args) {
int[] arr= {10,34,119,1,5,7,45};
selectSort(arr);
}
public static void selectSort(int arr[]) {
//假定第一个数是最小值
for(int i = 0;i < arr.length;i++) {
int minIndex = i;
int min = arr[minIndex];
for(int j = i+1; j <arr.length; j++ ) {
if(min>arr[j]) {//min不是最小数
minIndex = j;
min = arr[j];
}
}
if(minIndex!=i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
System.out.println("第"+(i+1)+"轮");
System.out.println(Arrays.toString(arr));
}
}
}
堆排序
堆是具有以下性值的完全二叉树:每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆。
一般升序采用大顶堆,降序采用小顶堆
堆排序的基本思想
- 将待排序序列构造成一个大顶堆
- 将根节点与末尾元素交换
- 将剩余元素重新构造成一个大顶堆,重复2
非递归
public class HeapSort {
public static void main(String[] args) {
//·升序排列
int[] arr = {4,6,8,5,9,123,2,-12,-13};
headSort(arr);
}
public static void headSort(int[] arr) {
int temp = 0;
System.out.println("堆排序");
//分步
//adjustHeap(arr, 1, arr.length);
//System.out.println("第一次"+Arrays.toString(arr));
//adjustHeap(arr, 0, arr.length);
//System.out.println("第二次"+Arrays.toString(arr));
//1.完整构建大顶堆
for(int i = arr.length /2 - 1; i >= 0 ;i--) {
adjustHeap(arr, i, arr.length);
}
//2.将对顶元素与末尾元素交换,将最大元素沉到数组末端
//3.重新调整结构使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行,直到整个序列有序
for(int j = arr.length -1 ; j>0 ;j--) {
//·交换
temp = arr[j];
arr[j] =arr[0];
arr[0] =temp;
adjustHeap(arr, 0, j);
}
System.out.println(Arrays.toString(arr));
}
//·将一个数组调整成一个大顶堆
/**
* 功能:将以i节点为跟的子树调整为大顶堆
* @param arr 数组
* @param i 非叶子节点 在数组中的索引
* @param length 有多少个非叶子节点
*/
public static void adjustHeap(int[] arr,int i ,int length) {
//·取出当前元素的值
int temp = arr[i];
//·开始调整
//1.k 是 i节点的左子节点
for(int k = i * 2 + 1;k < length; k = k * 2 + 1) {
if( arr[k] < arr[k+1] && k + 1 < length ) {//·左子节点的值小于右子节点
k++;//指向右子节点
}
if(arr[k] > temp) {//·子节点大于父节点
arr[i] = arr[k];//·将较大的值赋给父节点
i = k;//i指向k 继续循环比较
}else {
break;
}
}
//·结束循环后 已经将以i为父节点的树调整完毕
arr[i] = temp;//将temp的值放到调整后的位置
}
}
递归
public class HeapSort2 {
public static void main(String[] args) {
int[] arr = {4,6,8,5,9,123,2,-12,-13};
heapSort(arr);
}
public static void heapSort(int[] arr) {
//构建大顶堆
for(int i = arr.length / 2 - 1; i >= 0; i-- ) {
adjustHeap(arr, i, arr.length);
}
//交换堆顶和末尾元素
int temp = 0;
for(int j = arr.length -1 ; j>0 ;j--) {
//·交换
temp = arr[j];
arr[j] =arr[0];
arr[0] =temp;
adjustHeap(arr, 0, j);
}
System.out.println(Arrays.toString(arr));
}
public static void adjustHeap(int[] arr, int i, int len) {
//左子节点
int left = 2 * i + 1;
//右子节点
int right = 2 * i + 2;
//默认当前节点值最大
int largestIndex = i;
if(left < len && arr[left] > arr[largestIndex]) {
largestIndex = left;
}
if(right < len && arr[right] > arr[largestIndex]) {
largestIndex = right;
}
if(largestIndex != i) {
//交换
int temp = arr[i];
arr[i] = arr[largestIndex];
arr[largestIndex] = temp;
//交换之后 子节点值变了 继续调整
adjustHeap(arr, largestIndex, len);
}
}
}
插入排序
直接插入排序
基本思想:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表只包含一个元素,无序表包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把他的排序码依次与有序元素的排序码比较,将它插入到合适的位置,使之成为新的有序表
public class InsertSort {
public static void main(String[] args) {
int[] arr= {40,34,119,1,51,7,45};
insertSort(arr);
}
public static void insertSort(int[] arr) {
//·使用for循环从二个数开始
for(int i = 1;i< arr.length;i++) {
//·保存第i位的值
int insertVal = arr[i];
//·前一位的位置
int insertIndex = i - 1;
//insertIndex>= 0 保证在给insertVal找位置时不越界
//如果insertVal <arr[insertIndex]),就是还没找到位置
//需要将insertIndex位的数往后移一位
while(insertIndex >=0 && insertVal <arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];
insertIndex--;
}
arr[insertIndex + 1] = insertVal;
System.out.println(Arrays.toString(arr));
}
}
}
希尔排序
基本思想:把数组按下标的一定增量分组,对每组使用直接插入排序算法,随着增量逐渐减少,每组包含的元素 越来越多,当增量减至1时,整个文件被分成一组,结束。
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8,9,1,7,2,3,5,4,0};
}
public static void ShellSort(int arr[]) {
//第一轮:将10个数据分成5组
/*int temp = 0;
for(int i =5;i<arr.length;i++) {
//遍历各组中所有的 元素,步长5
for(int j = i-5;j >= 0;j-=5) {
if(arr[j] > arr[j+5]) {
//如果当前元素大于同组的那个数,则交换
temp = arr[j];
arr[j] = arr[j+5];
arr[j+5] = temp;
}
}
}
*/
//交换法
for(int gap = arr.length/2;gap > 0;gap /=2 ) {
int temp = 0;
for(int i =gap;i<arr.length;i++) {
//·遍历各组中所有的 元素,步长gap
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 ) {
//对第gap个元素,逐个对其所在的组进行直接插入排序
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;
}
//退出循环后,就给temp找到位置
arr[j] = temp;
}
}
}
}
}
归并排序
public class MergeSort {
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;
//向左递归分解
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数组
//·直到有一边为空
while( i <= mid && j <= right ) {
//·左边序列的当前元素小于等于右边序列的当前元素
//·将左边 的元素拷贝到temp
//i++,t++
if(arr[i] <= arr[j]) {
temp[t++] = arr[i++];
//i +=1;
//t +=1;
}else {
temp[t++] = arr[j++];
//j +=1;
//t +=1;
}
}
//(二)
//·把还有剩余的数组填充到temp
while(i <=mid) {//·说明左边还剩有元素
temp[t++] = arr[i++];
//t +=1;
//i +=1;
}
while(j <=right) {//·说明右边还剩有元素
temp[t++] = arr[j++];
//t +=1;
//j +=1;
}
//(三)
//·将temp数组拷贝到arr
//t = 0;
//int tempLeft = left;
//while (tempLeft <= right) {
// arr[tempLeft] = temp[t];
// t +=1;
// tempLeft +=1;
//}
int k =0;
for(int templeft = left; templeft <= right; templeft++) {
arr[templeft] = temp[k++];
}
}
}