算法总结之十种内部排序算法

一、1、首先推荐一个算法的可视化的一个网站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html.

二、O(n*n)--双循环

1、冒泡排序--两两对换

package Sort;

public class BubbleSort {
	public static void BubbleSort(int a[]){
		int len = a.length;
		/*外循环的目的是:
			考虑到最坏的情况即:
				如果整个数组全部倒序的话
					len个元素,要比较len-1次	
		*/
		for(int i = 0;i < len;i++) {
			/*内循环目的是:
				考虑最坏的情况
					如果数组的第n个元素是第n大的元素,那么从第n个元素一直交换到倒数第n个需要        
                    len-1 - j 次 
			*/
			for(int j = 0;j < len - 1;j++){
				if(a[j+1] < a[j]){
					int temp = a[j];
					a[j] = a[j+1];
					a[j+1] = temp;	
				}
			}
		}
	}
	//改进BubbleSort
	/*
	考虑到什么时候bubbleSort停止了排序
		当数组中的元素的顺序从小到大时候-->内循环的 if(a[j+1] < a[j]) -->目的是遍历数组中所有 
         相邻两个是否符合顺序
		-->因为只要数组元素不符合顺序的话-->遍历数组中的所有相邻两个元素一定存在不符合顺序相邻两个元素-->反之如果
		数组中所有相邻两个之间均符合顺序的话-->就可以得到整个数组是顺序的
	*/
	public static void BubbleSort_1(int a[]){
		int len = a.length;
		/*外循环的目的是:
			考虑到最坏的情况即:
				如果整个数组全部倒序的话
					len个元素,要比较len-1次	
		*/
		for(int i = 0;i < len;i++) {
			/*内循环目的是:
				考虑最坏的情况
					如果数组的第n个元素是第n大的元素,那么从第n个元素一直交换到倒数第n个需要len-1 - j 次 
			*/
			boolean flag = true;
			for(int j = 0;j < len - 1;j++){
				if(a[j+1] < a[j]){//这里写等于小于就会导致算法的不稳定//不稳定没排序之前的 ai 在 aj前面(ai <= aj),
					int temp = a[j];
					a[j] = a[j+1];
					a[j+1] = temp;
					flag = false;	
				}
			}
			if(flag)
				break;
		}
	}
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10,1,10);//自己创建的方法用来生成随机数组
		for(int i:a)
			System.out.print(i+" ");
		BubbleSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
		
		/*System.out.println("");
		a = RandomArray.Array(10);
		BubbleSort_1(a);
		for(int i:a)
			System.out.print(i+" ");
		 */
	}

}

2、插入排序--选一插入

package Sort;
/**
 * 2019/3/10
 * @author Administrator
 */
/*
 * 算法描述:
 * 	指针首先指向第一个元素,然后指向第一个元素右面的元素,如果指针指向的元素比第一个元素小就移动到第一个元素的左面
 * 	如此心来的元素移动到最后一个比其大的元素的右面
 *  若比第一个元素大,不动,指针向右指到下一个元素
 */
public class InsertSort {
	//10 5 4 5 3 1 10 8  3 8 
	// 5 10 4 5 3 1 10 8 3 8
	// 
	public static void insertSort(int a[]){
		int len = a.length;
		/*
		 * 外循环的目的:
		 * 	逐个将第i个元素插入到前 i 个元素中
		 */
		for(int i = 1;i < len;i++){
			int p = i - 1;
			int insertElement = a[i];
			/*	while循环的目的:
			 * 		插入第i个元素的时候,
			 * 		两两进行比较如果第i个元素的值小于
			 * 		第i个元素值前面的元素就交换第i个元素值与第p个元素的值
			 * 		一直到第i个元素的值大于其前面的元素的值为止或者到达第一个元素为止 
			 */
			while(p >= 0&&insertElement < a[p]){
				int temp = a[p];
				a[p] = insertElement;
				a[p+1] = temp;
				p--;
			}
		}
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10);
		
		for(int i:a)
			System.out.print(i+" ");
		insertSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
	}

}

3、希尔排序--分组的插入排序

package Sort;

public class ShellSort {
/*shellSort是对InsertSort的一种改进算法
 * 思想是:
 * 	改良的出发点是减少while语句的使用和减少比较的次数
 * 	操作:
 * 		分组
 * 		插入
 * 		分组
 */
	public static void shellSort(int a[],int gap){
		int len = a.length;
		
		for(int i = gap;i < len;i = i + gap){
			int p = i - gap;
			int element = a[i];
			
			while(p >= 0 && a[p] > element){
				int temp = a[p];
				a[p] = element;
				a[p+gap] = temp;
				p = p - gap;
			}
		}
	}
	
	public static void shellSort(int a[]){
		shellSort(a,5);
		shellSort(a,2);
		shellSort(a,1);
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10);
		
		for(int i:a)
			System.out.print(i+" ");
		shellSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
	}

}

4、选择排序--逐步选取

package Sort;

public class SellectionSort {
	/*
	 * 选择排序与插入排序有些类似不同的是
	 * 	插入排序是将第i个元素插入到前i个元素中间
	 * 	选择排序是从第i到第len-1个元素中选取一个最小的元素
	 * 	与第i个元素进行交换
	 */
	public static void sellectionSort(int a[]){
		int len = a.length;
		/*外循环的目的:
		 * 	从第i个元素之前的元素都是已经排序好的
			含义就相等于 当i = 0 的时候找最小的元素
						  i = 1 的时候找次小的元素
						  i = 2 的时候找次次小的元素
						  以此类推
		 */
		
		for(int i = 0;i < len;i++){
			int minIndex = i;
			
			/*
			 * 内循环的目的:
			 * 	寻找第i+1个到第len-1个元素中最小的元素的index
			 */
			for(int j = i + 1;j < len;j++){
				if(a[j] < a[minIndex]){
					minIndex = j;	
				}
			}
			
			/*
			 * 这一步交换第i+1个到第len-1个元素中最小的元素与第i个元素
			 */
			
			int temp = a[minIndex];
			a[minIndex] = a[i];
			a[i] = temp;
		
			}
	}
	
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10,1,10);
		for(int i:a)
			System.out.print(i+" ");
		sellectionSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
	}

}

三、O(n*logn) --运用到递归

1、归并排序

package Sort;
/*
 * 归并的思想:
 * 	将数组长度一次又一次的分割成两部分知道当一组数组的元素小于等于1的时候
 * 	在返回到上一次数组元素大于1但小于4的状态进行下一个分割,当这次分割成数组
 * 	元素的数量小于等于1的时候在进行合并。(如果对递归的这部分不太了解可以进行一步一步的debug了解递归的含义-->程序只有当把一个递归语句运行到return的时候才会进行下一步操作)
 * 	(关于递归算法后更)
 * 	因此可得递归的作用知识对数组进行等元素分割,真正对数组元素排序的是merge
 */
public class MergeSort {
	
	public static void mergeSort(int a[]){
		if(a.length <= 1){
			return ;
		}
		
		/*
		 * 下面语句的目的是将数组元素分为两部分直到
		 * 这俩个部分元素只有一个的时候在return进行merge
		 */
		int len = a.length;  //当前整个数组的长度
		int firstLength = len / 2;	//第一个数组的长度	
		int firstHalf[] = new int[firstLength];//
		System.arraycopy(a,0,firstHalf,0,firstLength); //将当前数组的以第一个元素开始长度为firstLength的元素全部复制到firstHalf数组内
		mergeSort(firstHalf);//这一部分的数组进入递归
					
		//当上一部分的数组递归到只有一个元素的时候返回然后进行下面的语句
		int secondLength = len - firstLength;//第二部分的数组的长度等于当前整个数组的长度--第一部分的数组的长度
											//这里可能会写成 len / 2 是不对的 因为如果 len为奇数那么两次整除的值相加便不是len了例如 第一次 3 / 2 = 1 
																															//第二次 3 / 2 = 1 	
		int secondHalf[] = new int[secondLength];//
		System.arraycopy(a,firstLength, secondHalf,0,secondLength);//将当前数组的以第firstLength个元素长度为secondLength的元素复制到secondHalf中
		mergeSort(secondHalf);//对这一部分的数组进行递归
		//当上一部分的数组递归到只有一个元素的时候返回然后进行下面的语句
		int temp[] = meger(firstHalf,secondHalf);//对已经得到的两部分进行merge
		System.arraycopy(temp,0,a,0,temp.length);//对当前这两部分merge结束之后这一程序结束相当于return当还有递归没有结束的时候再一次运行这个程序
	}
	
	
	public static int[] meger(int b[],int c[]){
		int len1 = b.length;
		int len2 = c.length;
		int temp[] = new int[len1+len2];
		
		int p1 = 0;
		int p2 = 0;
		int p3 = 0;
		
		while(p1 < len1 && p2 < len2){
			if(b[p1] < c[p2]){
				temp[p3++] = b[p1++];
			}else{
				temp[p3++] = c[p2++];
			}
		}
		while(p1 < len1){
			temp[p3++] = b[p1++];
		}
		while(p2 < len2){
			temp[p3++] = c[p2++];
		}
		
		return temp;
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10,1,10);
		for(int i:a)
			System.out.print(i+" ");
		mergeSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");

	}

}

2、快速排序

package Sort;
/*
 * quickSort与mergeSort相似
 * 不同之处是:
 * 	quickSort将重心放在如何使得将数组进行划分使得划分成的两部分一部分小于一个数另一部分大于这一个数
 * 	mergeSort目的是将数组划分后进行合并
 */

	
public class QuickSort {
	/* quickSort提高效率的一个方法就是对主元的选取要准确
	 * 这个方法对主元的选取并不那么高效
	 * */
	public static int partition(int a[],int b,int e){
		int privot = a[b];
		int p1 = b+1;
		int p2 = e;
		
		while(p1 <= p2){ //这一个while的条件可以写 p1 <= p2 也可以写p1 < p2
			if(a[p1] <= privot){    //考虑一下临界状态当p1 == p2的时候              
									//p1 == p2 -->这两个指针指向的元素是相同的-->无论的这个元素大于
								  //主元(p2-- -->p2所指向的元素是小于主元的)或者小于主元p1++(p2指向的元素小于主元)
								  //只要交换p2指向的元素与主元就可以了
				p1++;             
			}else{					//如果写成p1<p2的话还要再写判断p1 p2共同指向的元素是大于主元还是小于主元                
				int temp = a[p1];
				a[p1] = a[p2];
				a[p2] = temp;
				p2--;
			}
		}
		
		int temp = a[p2];
		a[p2] = a[b];
		a[b] = temp;
		
		return p2;
	}
    public static void quickSort(int a[],int b,int e){
		if(b > e)
			return;
		int q = partition(a,b,e);
		quickSort(a,b,q-1);
		quickSort(a,q+1,e);
	}
	
	public static void main(String[] args) {
		int a[] = {3,1,4,5,7,3,4,0,9,2};
		quickSort(a,0,a.length-1);
		for(int i:a)
			System.out.print(i+" ");

	}

}

四、O(n) --类桶排序

1、桶排序--桶是链表

package Sort;

import java.util.Collections;
import java.util.LinkedList;

public class BucketSort {
	
	public static void bucketSort(int a[]){
		int buckets = 10;
		LinkedList list[] = new LinkedList[buckets];  //10是桶的个数,可以根据数组元素的数量进行设置
		for(int i = 0;i < buckets;i++){
			list[i] = new LinkedList();
		} //--初始化 list
		
	/*	for(LinkedList l:list)
			l = new LinkedList();
		*///---为什么不能用这个进行初始化
		
		int len = a.length;
		
		//寻找数组中最大的元素
		int max = a[0];
		for(int i = 1;i < len;i++){
			if(max < a[i])
				max = a[i];
		}
		
		for(int i = 0;i < len;i++){
			int index = buckets*a[i]/(max+1);
			list[index].add(a[i]);
		}
	/*	for(int i = 0;i < buckets;i++){
			Collections.sort(list[i]);
		}*/
		
		for(LinkedList l:list)
			Collections.sort(l);   //偷个懒直接用api
		
		int p = 0;
		for(int i = 0;i < buckets;i++){
			while(!list[i].isEmpty()){
				a[p] = (int) list[i].remove(0);
				p++;
			}
		}
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(100,1,9000);
		for(int i:a)
			System.out.print(i+" ");
		bucketSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
			

	}

}

2、计数排序--桶是数组

package Sort;
/*计数操作--
 * 	思想是--用空间换时间
 * 	开辟一个足够大的空间数组temp
 * 	如果是对数组a进行排序的话
 * 	a第i个元素的值作为temp数组index,即 temp[a[i]] == temp[a[i]]++;
 * 	
 * 缺陷
 * 	不能对浮点数进行排序(这里指的浮点数是指数组中的元素的浮点位数不一样)
 * 	不能同时对含有重复数的与有负数的数组进行排序
 * 	 	
 */
public class CountSort {
	
	public static void countSort(int a[]){
		//找到最大的元素
		int max = a[0];
		int len = a.length;
		for(int i = 1;i < len;i++){
			if(max < a[i]){
				max = a[i];
			}
		}
		int temp[] = new int[max+1]; //这里max为什么要加1  有没有必要?---必须要加1.因为当有最后写入a[i]是temp的下标,数组的下标是从0开始的没有max下标
		//对数组temp进行赋值
		for(int i = 0;i < len;i++){
			temp[a[i]] = temp[a[i]] + 1;
		}
			
		//将temp的index顺序输出
		int p = 0;
		for(int i = 0;i < max+1;i++){
			while(temp[i] != 0){
				a[p] = i;
				temp[i] = temp[i] - 1;
				p++;
			}
		}
	}
	public static void main(String[] args) {
		int a[] = RandomArray.Array(100,1,10000);
		for(int i:a)
			System.out.print(i+" ");
		countSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");

	}

}

3、基数排序--桶是线性表

package Sort;
/*
 * 思想是:基数 radix 【数】基数;根值;记数根;【植】根
 * 		对数组元素中的每一个数值的每一个位上进行分布到各个桶中然后再出桶
 * 		一直循环到最大的那个元素的位数
 */

import java.util.ArrayList;

public class RadixSort {
	
	public static void radixSort(int a[],int radix,int temp[]){
		int len = a.length;
		ArrayList list[] = new ArrayList[10];
		//初始化list数组中的ArrayList
		for(int i = 0;i < 10;i++)
			list[i] = new ArrayList();  ///极重要
		
		//入桶
		for(int i = 0;i < len;i++){
			int number = temp[i] % 10;
			list[number].add(a[i]);
		}
		
		
		int p = 0;  
		//出桶
		for(int i = 0;i < 10;i++){
			int p1 = 0;
			while(!list[i].isEmpty()){
				a[p] = (int) list[i].remove(0);	//因为是移去的所以每次都是第一个		
				p++;    //p1++
			}
		}
		
		for(int i = 0;i < len;i++){
			temp[i] = (int) (a[i] / (Math.pow(10,radix)));  //
		}
		
	}
	
	public static void radixSort(int a[]){
		int max = a[0];
		int len = a.length;
		for(int i = 1;i < len;i++)
			if(max <= a[i])
				max = a[i];
		int radix = String.valueOf(max).length();
		int temp[] = new int[a.length];
		//temp = a;  //这个语句的含义是啥子:不能将a直接赋值给temp temp = a 是将a的地址给了temp如果改变temp中的元素a中的元素也会改变
		int p = 0;
		for(int i:a){
			temp[p] = i;
			p++;
		}
		
		int count = 1;
		while(radix != (count-1)){
			radixSort(a,count,temp);
			count++;
		}
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(100,1,9000);
		for(int i:a)
			System.out.print(i+" ");
		radixSort(a);
		System.out.println("");
		for(int i:a)
			System.out.print(i+" ");
		
	}

}

五、堆排序

package Sort;

import java.util.ArrayList;
/*
 * 利用数组构建一个特殊的堆,然后将堆的数据按照特殊的方式重写到数组上面
 * 1、如何用数组构建堆
 * 		除数组的第一个元素每一个元素都有父节点--数组中的元素的父节点的求法是  (i - 1)/ 2
 * 		除叶子节点外,数组中的每一个元素都有子节点,已知一个父节点再数组中的位于第i个那么其两个子节点分别位 2*i+1 2*i+2
 * 2、构建什么样特殊的堆
 * 		如果是递增的:
 * 			父节点比子节点小
 * 			左孩子比右孩子小
 * 3、怎么让堆输出重写到数组上面
 */
public class HeapSort {
	/*public static void heapSort(int a[]){
		int len = a.length;
		int p = 0;
		int left = 2*p + 1;
		int right = 2*p + 2;
		
		int temp[] = new int[len];
		temp[p] = a[p];
		
		if(a[2*p+1] < temp[p]){
			int t = temp[p];
			temp[p] = a[2*p+1];
			temp[p*2+1] = temp[p];
		}else{
			temp[2*p+1] = a[2*p+1]; 
		}
	}*/
	
	public static ArrayList<Integer> list = new ArrayList<Integer>();
	
	public static void add(int a){
		list.add(a);
		int currentIndex = list.size()-1;
		while(currentIndex > 0){
			
			int parentIndex = (currentIndex - 1) / 2;
			if(list.get(currentIndex) > list.get(parentIndex)){
				int temp = list.get(currentIndex);
				list.set(currentIndex,list.get(parentIndex));
				list.set(parentIndex,temp);
			}else{
				break;
			}
			currentIndex = parentIndex;	
		}
	}
	
	public static int remove(){
		int removeObject = list.get(0);
		
		/**将数组中的最后一个元素(堆的最下面的右边的一个元素)设置为 根 之后将其删除*/
		list.set(0, list.get(list.size() - 1));
		list.remove(list.size() - 1);
		
		
		int currentIndex = 0;
		while(currentIndex < list.size()){
			int leftChildIndex = 2*currentIndex + 1;
			int rightChildIndex = 2*currentIndex + 2;
			//find the maximum between two childern
			if(leftChildIndex >= list.size())	break;   //the tree is heap
			
			int maxIndex = leftChildIndex;
			
			if(rightChildIndex < list.size()){
				if(list.get(maxIndex).compareTo(
						list.get(rightChildIndex))<0){
					maxIndex = rightChildIndex;
				}
			}
			
			//swap if the current node is less than the maximum
			if(list.get(currentIndex).compareTo(
					list.get(maxIndex)) < 0){
				int temp = list.get(maxIndex);
				list.set(maxIndex, list.get(currentIndex));
				list.set(currentIndex, temp);
				currentIndex = maxIndex;
			}else
				break;//the tree is a heap
		}
		return removeObject;
	}
	
	public static void heapSort(int[] list){
		//add elements to the heap
		for(int i = 0;i < list.length;i++)
			add(list[i]);
		
		for(int i = list.length - 1;i >= 0;i--)
			list[i] = remove();
	}
	
	public static void main(String[] args) {
		int a[] = RandomArray.Array(10,1,10);
		for(int i:a){
			System.out.print(i+" ");
		}
		heapSort(a);
		System.out.println("");
		for(int i:a){
			System.out.print(i+" ");
		}
	}

}
发布了26 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41926640/article/details/88383825