首页 > 编程 > Java > 正文

java实现排序算法之选择排序(简单选择排序和堆排序)

2019-11-08 02:08:13
字体:
来源:转载
供稿:网友

选择排序:就是一次从待排序列中选择一个最大元素或最小元素确定其最终位置,其中最常用的就是:简单选择排序和堆排序,下面分别讲解这两个算法:

简单选择排序:算法思想:第一趟从待排序列中选择一个最小的元素和第一元素交换位置,然后第二趟从剩下的元素中选择最小的元素和第二个元素交换位置,然后依次类推,直到所有元素都确定其最终的位置,排序结束。

稳定性:不稳定

时空复杂度与初始状态是否有关:有关(移动次数与初始状态有关,比较次数与初始状态无关)

时间复杂度:O(n^2):比较次数均是n(n-1)/2,移动次数最好情况为0,最坏情况不超过3(n-1)c次

空间复杂度:O(1)

下面是java实现代码:

public class Main {		public static void main(String[] args) {		int []a={4,9,2,7,1,8,9,5,3};		easySelectSort(a);		System.out.PRintln(Arrays.toString(a));	}	public static void easySelectSort(int []a){				for(int i=0;i<a.length;i++){			int min=a[i];//min用来保存每一趟要确定位置的元素数组			int position=i;//position用来保存每一趟要交换的元素位置,即每趟最小的元素所在位置,			for(int j=i;j<a.length;j++){//for循环寻找最小元素				if(a[j]<min){					min=a[j];					position=j;				}			}			a[position]=a[i];			a[i]=min;//将找到的元素放在最终位置上					}	}}

堆排序:

堆排序是重点也是难点,它是一种树形选择排序方法,它的思想就是:在排序过程中,将待排序数组看成是一个完全二叉树的顺序存储结构,这里我们就要知道完全二叉树的顺序存储的特点,那就是若有一个元素在数组中的位置为i,则其左孩子节点一定存在数组中下标为2i的位置上,其右孩子节点一定存在数组中下标为2i+1的位置上,否则就不存在,注意这里的数组下标是从1开始的,0中不存放元素,若数组下标从0开始存放元素,其父节点与子节点的对应关系也会发生相应的改变,具体看下面java代码。然后做堆排序就要用到这个完全二叉树的顺序存储的特点,来寻找树中对应关系,然后做相应的交换。

然后我们还要了解堆的概念,n个关键字序列L[1,2,3,4,.....n]称为堆,当且仅当该序列满足:1:L(i)<=L(2i)且L(i)<=L(2i+1) 或 2:L(i)>=(2i)且L(i)>=(2I+1); 满足第一种情况的称为小根堆,满足第二种情况的称为大根堆,我们可以看到,在大根堆中,最大的元素存放在根节点中,且对任意非根节点,它的值小于或等于其双亲节点的值,小根堆的定义正好相反,根节点是最小的元素。

接下来我们还要知道,在堆中不能直接删除其根节点元素,这样会破坏二叉树的结构,当我们要删除根节点时,必须先把根节点和最后一个叶节点进行交换,然后在将交换后的根节点删除,然后重新调整二叉树使其成为堆。

算法思想:(我们以大根堆为例)

首先就是将要排序的数组进行建堆操作,使其具有堆结构,建堆的过程:就是从最后一个非叶节点开始,比较其与其子节点的关键字大小,若子节点关键字较大,则与其父节点交换位置,若交换的子节点还有子节点也要进行比较进行向下调整的操作,直到交换的节点无子节点为止,然后逐个向前遍历非叶节点,直到所有的非叶节点遍历完毕,则建堆操作完成,然后将根节点和堆最后一个叶节点进行交换,将最后叶节点从堆中删除,然后进行上述中的对下调整操作,从新时期变成堆结构,然后重复交换调整操作,直到堆中无元素或只有一个元素,则排序完成。

稳定性:不稳定

时空复杂度与初始状态是否有关:有关(比较次数无关,交换次数有关)

时间复杂度:建堆时间O(n),之后n-1次向下调整,调整时间O(log2^n)所以总时间复杂度:O(nlog2^n)

空间复杂度:O(1)

下面是java实现代码:

public class Main {    public static void main(String[] args) {    	int []a={4,9,2,7,1,8,9,5,3};    	System.out.println("待排序序列"+Arrays.toString(a));         int len=a.length;        heapSort(a, len);        System.out.println("堆排序后序列"+Arrays.toString(a));        }    public static void heapSort(int []data,int len ){    	buildMaxHeap(data,len);    	System.out.println("建堆后序列"+Arrays.toString(data));    	for(int i=len-1;i>0;i--){//堆排序    		swap(data,0,i);//每一趟将根节点与最后的叶节点交换    		adjustDown(data, 0, i);    	}    }      public static void buildMaxHeap(int[] data, int len){       for(int i=(len-1)/2;i>=0;i--){//从最后一个节点的父节点开始向上遍历节点进行向下调整堆操作    	   adjustDown(data,i,len);       }    }      //向下调整为,父节点值与其子节点的值作比较,若父节点值小则交换    public static void adjustDown(int []data,int node,int len){    	while(node<len){//当node小于len的时候判断是否结束,与下面node=biggerIndex呼应,相当于递归结束条件    	    	//这里先假设node的左右节点均存在写出其索引值,后面在判断是否存在    	int leftIndex=node*2+1;//node*2+1为node的左子节点    	int rightIndex=node*2+1+1;//node*2+1+1为node的右子节点    	int biggerIndex = leftIndex;//biggerIndex保存其左右节点中较大的一个节点值,默认左节点    	if(leftIndex<len){ //判断左节点是否存在    		if(rightIndex<len){//判断右节点是否存在    			biggerIndex=data[leftIndex]>data[rightIndex]?leftIndex:rightIndex;//biggerIndex始终指向最大的子节点    		}    		else biggerIndex=leftIndex;    	}    	else break;//左右都无节点直接跳出循环    	if(data[biggerIndex]>data[node]){    		swap(data,biggerIndex,node);    		node=biggerIndex;//将与父节点交换后的节点复制给node进行向下调整操作,这里用了while循环来实现,当然也可以用递归来实现    	}else break;    	}	    }       private static void swap(int[] data, int i, int j) {          int tmp=data[i];          data[i]=data[j];          data[j]=tmp;      } }


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表