https://blog.youkuaiyun.com/lsh_2013/article/details/47280135
https://blog.youkuaiyun.com/wanglelelihuanhuan/article/details/51340290点击打开链接
https://www.cnblogs.com/alsf/p/6606287.html点击打开链接
最后的是java实现的
关于归并排序的比较https://www.cnblogs.com/nullzx/p/5968170.html点击打开链接
冒泡
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)
/**冒泡排序
* @param arr 数组
*/
public static void maopao(int[] arr)
{
for(int x=0;x<arr.length-1;x++)
{
for(int y=0;y<arr.length-x-1;y++)
{//减一避免越界
if(arr[y]>arr[y+1])
{
int temp=arr[y];
arr[y]=arr[y+1];
arr[y+1]=temp;
}
}
}
}
/** * 选择排序 * @param a 排序数组
首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。
时间复杂度:O(n^2),最优时间复杂度:O(n^2),平均时间复杂度:O(n^2)
*/ public static void selectionSort1(int[] a) {
int length = a.length;
int min;
int temp;
for (int i = 0; i < length; i++) {
min = i;
for (int j = i + 1; j < length; j++) {//找出最小的数
if (a[j] <a[min]) {
min = j;
}
}
temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
插入排序
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)
/**
* 插入排序
* @param a 排序数组
*/
public static void insertionSort(Comparable[] a) {
int length = a.length;
Comparable temp;
for (int i = 1; i < length; i++) {
for (int j = i; j > 0 && a[j]<a[j - 1]; j--) {
temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
}
}
}
快排:
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 步骤是:从右向左查找第一个比基数小的交换,从左向右找第一个比它大的交换
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
- 时间复杂度:O(n^2),最优时间复杂度:O(nlogn),平均时间复杂度:O(nlogn)
/**快速排序方法*/
//声明数组 int[] arr = {49,38,65,97,76,13 ,27};
/* data:要排序的数组
* start:选取的是第一个数,这里是索引号,这里是49,始终拿这个数和其他数比较,
* 因此,位置也就串这个数所在的索引,
* end;最后一个元素,这里是索引号,这里是27
*/
public static void quickSort(int[] arr, int start, int end) {
int i = start; //相当于i,左 索引
int j = end; //相当于j, 右 索引
if (i >= j) { // 判断是否到中间了 ,到中间返回// 1 2
return; //返回
}
//确定指针方向的逻辑变量,也就是从左搜索还是向右搜索
boolean flag=true; //false:左->右 true:右->左
while (i != j) { //如果i==j证明第一趟结束,每趟的标准值仅是一个,例如第一趟被比较值为49,
if (arr[i] > arr[j]) {//右比它小的
//交换数字 :所有比它小的数据元素一律放到左边,所有比他大的数据元素一律放到右边,
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
//只有经过数的交换后,才能把游标的移动位置改变,移动书序是交替改变
//决定下标移动,还是上标移动 ,游标更改 走下一个数据
// flag = (flag == true) ? false : true;
flag=!flag;
}
//将指针向前或者向后移动 ,第一次从左-》右,第二次从右-》左
if(flag) {//true,右---》左
j--;
}else{//false 左---》右
i++;
}
} //1 2
//到此,数组的数据排列位置为:
//第一次到该位置,data的值是:[27, 38, 13, 49, 76, 97, 65]
//将数组分开两半,确定每个数字的正确位置
//i=3,j=3
i--; //
j++;
//i=2 j=4 start=0 end=6
quickSort(arr, start, i); //也就是 27 38 13在快速排序
quickSort(arr, j, end); // 也就是 76, 97, 65在快速排序
}
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
/**
* 希尔排序
*/
public static void shellSort(int[] arr) {
int length = arr.length;//数组中元素个数
int h = 1; // 步长
int temp;
// 选择一个步长序列
System.out.println(h);
while (h < length / 3) {
h = 3 * h + 1;// 1 4 13
System.out.println(h);
}
// 按照步长序列 ,将待排序数组分割成h个子序列后进行插入排序
while (h >= 1) {
for (int i = h; i < length; i++) {
for (int j = i; j >= h && arr[j] < arr[j - h]; j -= h) {
temp = arr[j];
arr[j] = arr[j - h];
arr[j - h] = temp;
}
}
h /= 3;
}
}
归并排序
自顶向下的排序算法就是把数组元素不断的二分,直到子数组的元素个数为一个,因为这个时候子数组必定是已有序的,然后将两个有序的序列合并成一个新的有序的序列,两个新的有序序列又可以合并成另一个新的有序序列,以此类推,直到合并成一个有序的数组。
自底向上的归并排序算法的思想就是数组中先一个一个归并成两两有序的序列,两两有序的序列归并成四个四个有序的序列,然后四个四个有序的序列归并八个八个有序的序列,以此类推,直到,归并的长度大于整个数组的长度,此时整个数组有序。需要注意的是数组按照归并长度划分,最后一个子数组可能不满足长度要求,这个情况需要特殊处理。自顶下下的归并排序算法一般用递归来实现,而自底向上可以用循环来实现。
/*
* 归并排序
* */
//自顶向下
public static void MergeSortUpToDown(int[] A){
@SuppressWarnings("unchecked")
//创建合并两个有序序列的辅助数组
int[] aux = (int[]) Array.newInstance(A.getClass().getComponentType(), A.length);
mergeSortUpToDown0(A, aux, 0, A.length-1);
}
public static void mergeSortUpToDown0(int[] A, int[] aux, int start, int end){
if(start == end)
return;
int mid = (start+end)/2;
mergeSortUpToDown0(A, aux, start, mid);
mergeSortUpToDown0(A, aux, mid+1, end);
//复制到辅助数组中,此时[start,mid] [mid+1, end]两个子数组已经有序
System.arraycopy(A, start, aux, start, end - start + 1);
//然后归并回来
int i = start, j = mid+1, k;
for(k = start; k <= end; k++){
if(i > mid){
A[k] = aux[j++];
}else
if(j > end){
A[k] = aux[i++];
}else
if(aux[i]<aux[j]){
A[k] = aux[i++];
}else{
A[k] = aux[j++];
}
}
}
//自底向上归并排序
public static void MergeSortDownToUp(int[] A){
@SuppressWarnings("unchecked")
int[] aux = (int[]) Array.newInstance(A.getClass().getComponentType(), A.length);
int len,i,j,k,start,mid,end;
//len表示归并子数组的长度,1表示,一个一个的归并,归并后的长度为2,2表示两个两个的归并,归并后的长度为4,以此类推
for(len = 1; len < A.length; len = 2*len){
//复制到辅助数组中
System.arraycopy(A, 0, aux, 0, A.length);
//按照len的长度归并回A数组,归并后长度翻倍
for(start = 0; start < A.length; start = start+2*len){
mid = start + len - 1;
//对于数组长度不满足2的x次幂的数组,mid可能会大于end
end = Math.min(start + 2*len - 1, A.length-1);
i = start;
//mid大于end时,j必然大于end,所以不会引起越界访问
j = mid+1;
//[start,mid] [mid+1, end]
for(k = start; k <= end; k++){
if(i > mid){
A[k] = aux[j++];
}else
if(j > end){
A[k] = aux[i++];
}else
if(aux[i]<aux[j]){
A[k] = aux[i++];
}else{
A[k] = aux[j++];
}
}
}
}
}
/**遍历数组元素
*
* @param arr 遍历数组
*/
public static void printArray(int[]arr)
{
//遍历数组元素
for(int i=0;i<arr.length;i++)
{
System.out.println(arr[i]);
}
}