You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Ways/README.md

236 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

1)冒泡排序
是相邻元素之间的比较和交换两重循环O(n2);所以,如果两个相邻元素相等,是不会交换的。所以它是一种稳定的排序方法
public static void main(String[] args) {
int[] score ={7,5,4,2,3,8}
for (int i = 0; i < score.length - 1; i++) {
// 比较相邻两个元素,较大的数往后冒泡
for (int j = 0; j < score.length - 1 - i; j++) {
if (score[j] > score[j + 1]) {
double temp = score[j + 1]; // 把第一个元素值保存到临时变量中
score[j + 1] = score[j]; // 把第二个元素值转移到第一个元素变量中
score[j] = temp; // 把临时变量(第一个元素的原值)保存到第二个元素中
}}}
(2)选择排序
每个元素都与第一个元素相比产生交换两重循环O(n2)举个例子5 8 5 2 9第一遍之后2会与5交换那么原序列中两个5的顺序就被破坏了。所以不是稳定的排序算法
int[] nums = {84,83,88,87,61};
for(int i = 0;i< nums.length-1;i++){
for(int j=i;j< nums.length-1;j++){
if(nums[i] > nums[j+1]){
int temp ;
temp = nums[i];
nums[i] = nums[j+1];
nums[j+1] = temp;}}}
(3)插入排序
插入排序是在一个已经有序的小序列的基础上一次插入一个元素。刚开始这个小序列只包含第一个元素事件复杂度O(n2)。比较是从这个小序列的末尾开始的。想要插入的元素和小序列的最大者开始比起,如果比它大则直接插在其后面,否则一直往前找它该插入的位置。如果遇见了一个和插入元素相等的,则把插入元素放在这个相等元素的后面。所以相等元素间的顺序没有改变,是稳定的。
public static void main(String[] args){
int[] nums = buildArray();
System.out.print("亲,您输入的初始数组是 : ");
printArray(nums);
//默认构造从左→右依次递增的序列
for(int i=1; i<nums.length; i++){
int j;
int temp = nums[i]; //temp是本趟待插入的数,之前从0~i-1的数全是从左→右有序递增。
for(j=i-1; j>=0&&nums[j]>temp; j--){
nums[j+1] = nums[j];
}
nums[j+1] = temp;
System.out.print("第"+i+"次直接插入排序后的数组:");
printArray(nums); }}
(4)快速排序
快速排序有两个方向左边的i下标一直往右走当a[i] <= a[center_index]其中center_index是中枢元素的数组下标一般取为数组第0个元素。而右边的j下标一直往左走当a[j] > a[center_index]。如果i和j都走不动了i <= j, 交换a[i]和a[j],重复上面的过程直到i>j。 交换a[j]和a[center_index]完成一趟快速排序。在中枢元素和a[j]交换的时候,很有可能把前面的元素的稳定性打乱,比如序列为 5 3 3 4 3 8 9 10 11 现在中枢元素5和3(第5个元素下标从1开始计)交换就会把元素3的稳定性打乱所以快速排序是一个不稳定的排序算法不稳定发生在中枢元素和a[j]交换的时刻。
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[] {9,4,6,8,3,10,4,6};
quickSort(arr,0,arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int low,int high) {
int p,i,j,temp;
if(low >= high) {
return;
}
//p就是基准数,这里就是每个数组的第一个
p = arr[low];
i = low;
j = high;
while(i < j) {
//右边当发现小于p的值时停止循环
while(arr[j] >= p && i < j) {
j--;
}
//这里一定是右边开始,上下这两个循环不能调换(下面有解析,可以先想想)
//左边当发现大于p的值时停止循环
while(arr[i] <= p && i < j) {
i++;
}
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
//i=j指针相遇把较小的arr[i]赋值给arr[0],较大的jp赋值给arr[i];
arr[low] = arr[i];//这里的arr[i]一定是小于p的,经过ij交换后i处的值一定是小于p的(j先走)
//把最后一个交换的array[i]赋值给arr[low],即arry[0];
arr[i] = p; //把较大的p赋值给arr[i]
quickSort(arr,low,j-1); //对左边快排
quickSort(arr,j+1,high); //对右边快排}}
(5)归并排序
归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。
public class myMergeSort {
static int number=0;
public static void main(String[] args) {
int[] a = {26, 5, 98, 108, 28, 99, 100, 56, 34, 1 };
printArray("排序前:",a);
MergeSort(a);
printArray("排序后:",a);
}
private static void printArray(String pre,int[] a) {
System.out.print(pre+"\n");
for(int i=0;i<a.length;i++)
System.out.print(a[i]+"\t");
System.out.println();
}
private static void MergeSort(int[] a) {
// TODO Auto-generated method stub
System.out.println("开始排序");
Sort(a, 0, a.length - 1);
}
private static void Sort(int[] a, int left, int right) {
if(left>=right)
return;
int mid = (left + right) / 2;
//二路归并排序里面有两个Sort多路归并排序里面写多个Sort就可以了
Sort(a, left, mid);
Sort(a, mid + 1, right);
merge(a, left, mid, right);
}
private static void merge(int[] a, int left, int mid, int right) {
int[] tmp = new int[a.length];
int r1 = mid + 1;
int tIndex = left;
int cIndex=left;
// 逐个归并
while(left <=mid && r1 <= right) {
if (a[left] <= a[r1])
tmp[tIndex++] = a[left++];
else
tmp[tIndex++] = a[r1++];
}
// 将左边剩余的归并
while (left <=mid) {
tmp[tIndex++] = a[left++];
}
// 将右边剩余的归并
while ( r1 <= right ) {
tmp[tIndex++] = a[r1++];
}
System.out.println("第"+(++number)+"趟排序:\t");
// TODO Auto-generated method stub
//从临时数组拷贝到原数组
while(cIndex<=right){
a[cIndex]=tmp[cIndex];
//输出中间归并排序结果
System.out.print(a[cIndex]+"\t");
cIndex++;
}
System.out.println()}}
(6)基数排序
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。
(7)希尔排序(shell)
希尔排序是按照不同步长对元素进行插入排序当刚开始元素很无序的时候步长最大所以插入排序的元素个数很少速度很快当元素基本有序了步长很小插入排序对于有序的序列效率很高。所以希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序我们知道一次插入排序是稳定的不会改变相同元素的相对顺序但在不同的插入排序过程中相同的元素可能在各自的插入排序中移动最后其稳定性就会被打乱所以shell排序是不稳定的。
import java.util.Arrays;
// 希尔排序对于大型数组排序效率很高,不需要额外的内存空间
public class 希尔排序 {
public static void shellSort(int[] a) {
int n = a.length;
// 设置增量,增量的取法有很多,这里是推荐取法
int h = 1;
while (h < n / 3) {
h = 3 * h + 1;
}
// 增量最小为 1 ,也就是相邻的两个元素比较
while (h >= 1) {
// 对相距 h 的两个元素插入排序
for (int i = h; i < n; i++) {
for (int j = i; j >= h && less(a[j], a[j-h]); j -= h) {
exch(a, j, j-h);
}
}
// 排序结束后,缩小增量,继续排序
h /= 3;
}
}
private static void exch(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
private static boolean less(Comparable v, Comparable w) {
// 若 v 小于 w 则返回负数
return v.compareTo(w) < 0;
}
public static void main(String[] args) {
int[] s = {4, 6, 1, 2, 3, 0};
System.out.println(Arrays.toString(s));
shellSort(s);
System.out.println(Arrays.toString(s));
}
}
(8)堆排序
我们知道堆的结构是节点i的孩子为2*i2*i+1节点,大顶堆要求父节点大于等于其2个子节点,小顶堆要求父节点小于等于其2个子节点。在一个长为n的序列,堆排序的过程是从第n/2开始和其子节点共3个值选择最大(大顶堆)或者最小(小顶堆),这3个元素之间的选择当然不会破坏稳定性。但当为n/2-1, n/2-2, ...1这些个父节点选择元素时,就会破坏稳定性。有可能第n/2个父节点交换把后面一个元素交换过去了,而第n/2-1个父节点把后面一个相同的元素没有交换,那么这2个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳定的排序算法
//数据结构-最小堆
static int[] Heap_Sort(int[] array){
int len = array.length;
//创建最小堆,PriorityQueue内部维护的数组默认长度是11
//为防止给的数组长度大于11,进堆时要扩展内部数组的长度
//所以初始化时,确定内部数组的长度等于我们传入的数组的长度
Queue<Integer> minHeap = new PriorityQueue<>(len);
for(int e : array){
minHeap.add(e);
}
//把堆顶(最小元素)投出,存在新数组中
for(int i = 0; i < len; i++){
array[i] = minHeap.poll();
}
return array;
}
总结:
排序法 平均时间 最差情形 稳定度 额外空间 备注
冒泡 O(n2) O(n2) 稳定 O(1) n小时较好
选择 O(n2) O(n2) 不稳定 O(1) n小时较好
插入 O(n2) O(n2) 稳定 O(1) 大部分排序时较好
基数 O(logRB) O(logRB) 稳定 O(n) B是真数(0-9)
R是基数(个十百)
Shell O(nlogn) O(ns) 1<s<2 不稳定 O(1) s是所选分组
快速 O(nlogn) O(n2) 不稳定 O(nlogn) n大时较好
归并 O(nlogn) O(nlogn) 稳定 O(1) n大时较好
O(nlogn) O(nlogn) 不稳定 O(1) n大时较好