排序算法

1概念

排序就是对数据元素序列建立某种有序序列的过程

2分类

内部排序:把待排序元素全部调入内存进行排序的过程;
外部排序:如果待排元素数据量太大,需要分批导入内存,排好序后再分批导出到磁盘和磁盘外存介质上的排序方法;(本文不讨论)

3评价标准

  1. 时间复杂度
  2. 空间复杂度
  3. 稳定性

4排序算法

4.1基于插入的排序

插入排序的基本思想:从初始有序的集合开始,不断的把新的数据元素插入到已排序的有序子集合的合适位置上,使子集合的元素个数不断增多,当子集合等于集合时,插入排序结束。常用的有直接插入排序和希尔排序两种。

4.1.1直接插入排序

1.原理:有n个数据待排序,存放在数组a中,初始时a[0]为有序子集合,第一次循环,将a[1]插入到有序子集合中,若a[0]<=a[1],说明序列已有序,a[1]不用动;若a[0]>a[1],将a[1]插入到a[0]之前。这样子集合大小增加到2。依次类推,直到子集合增加到n。
2. 时间复杂度:最好情况下(集合基本有序)O(n);最坏的情况(集合反序)O(n^2);平均复杂度(集合序列随机)O(n ^2);
3. 空间复杂度:O(1);
4. 稳定性:稳定
Java代码

public class InserSort 
{
	public static void insertsort(int[] a)
	{	int i,j,temp;
		for(i=1;i<a.length;i++)//假设a[0]已经有序,从a[1]开始插入,i从1开始
		{
			temp=a[i];
			for(j=i-1;j>-1;j--)//将每个元素与之前已经排好的元素依次比较,找到满足条件的插入位置
			{
				if(a[j]>=temp)
					{
						a[j+1]=a[j];
					}
				else 
				{
					break;
				}	
					
			}
			a[j+1]=temp;//插入元素
		}
	}
	public static void main(String[] args)
	{
		int[] a= {4,2,5,7,3,1,8,6};
		insertsort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+" ");
			
		}
		System.out.print("好嗨呦");
	}
}
4.1.2希尔排序

1.原理
把待排序元素分成若干小组,对同一组内元素进行插入排序;小组个数一次减小;但完成所有元素都在一个组内排序时过程结束。希尔排序又称为缩小增量排序。也是在分组概念上的直接插入排序。
2.时间复杂度:取决于增量的选取。
3. 空间复杂度:O(1);
4. 稳定性:不稳定

4.2基于选择的排序

选择排序的基本思想:每次从待排序元素中选择最小(大)的数据元素放到最前(后)面,数据元素集合不断缩小,当集合为空时过程结束。常用的有直接选择排序和堆排序两种。

4.2.1直接选择排序

1.原理:从待排序的数据元素集合中选择最小的元素与原始数据集合的第一个数据元素交换位置;然后从不包括第一个数据元素的集合中选择最小的元素与原始集合中第二个数据元素交换位置;重复,知道只剩一个元素为止。
2.时间复杂度:O(n^2);
3.空间复杂度:O(1);
4. 稳定性:不稳定。

4.2.1堆排序

1.最大堆:设数组a中存放了n个数据元素,下标从0开始,若下标满足:当2i+1<n时,有a[2i+1]<=a[i];当2i+2<n时,有a[2i+2]<=a[i],这样的数据结构成为最大堆。
2.最小堆:设数组a中存放了n个数据元素,下标从0开始,若下标满足:当2i+1<n时,有a[2i+1]>=a[i];当2i+2<n时,有a[2i+2]>=a[i],这样的数据结构成为最小堆。
3.堆的性质:(1)最大堆的根结点是堆中最大的元素,最小堆的根节点是最小的元素,堆的根结点成为堆顶元素。
(2)对于最大堆,从根结点到每个叶结点的路径上,数据递减有序;对于最小堆,从根结点到每个叶结点的路径上,数据递增有序;
4.堆排序原理:(1)把堆顶元素a[0]和当前最大堆(大根堆)的最后一个元素交换;
(2)最大堆元素个数减1;
(3)调整根结点使之满足最大堆定义;
重复以上过程直到数组为空。
5.时间复杂度:O(nlbn)
6.空间复杂度:O(1);
7. 稳定性:不稳定
java代码

public class HeapSort 
{
	public static void creatHeap(int[] a,int n,int h)
	{
		int i,j,temp,flag;
		i=h;//i为要创建堆的创建堆的根节点下标
		j=2*i+1;//j为i结点的左孩子下标
		temp=a[i];
		flag=0;
		while(j<n&&flag!=1)
		{
			if(j<n-1&&a[j]<a[j+1])j++;//寻找孩子中值较大者,让j为其下标
			if(temp>a[j])flag=1;//根结点大于孩子,已经满足最大堆定义,标记一下
			else
			{	
				//否则把a[j]上移
				a[i]=a[j];
				i=j;
				j=2*i+1;
			}
			a[i]=temp;
		}
	}
	public static void initcreatHeap(int[] a)
	{
		int n=a.length;
		for(int i=(n-1)/2;i>=0;i--)
		{
			creatHeap(a,n,i);
		}
	}
	public static void heapsort(int[] a)
	{
		int temp;
		int n=a.length;
		initcreatHeap(a);
		for(int i=n-1;i>0;i--)
		{
			temp=a[0];
			a[0]=a[i];
			a[i]=temp;
			creatHeap(a,i,0);
		}
	}
	public static void main(String[] args)
	{
		int[] a= {4,2,5,7,3,1,8,6};
		heapsort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+" ");
			
		}
		System.out.print("好嗨呦");
	}
}

4.3基于交换的排序

交换排序的基本思想:利用交换元素位置进行排序。常见的有冒泡排序和快速排序。

4.3.1冒泡排序

1.原理:设有n个数据待排序,存放在数组a中,循环进行n-1趟如下排序过程:第一趟,依次比较相邻两个元素a[i]和ai+1,若为逆序,则交换两个元素位置,否则不交换,最后最大元素将被放在a[n-1]中;第2趟时,循环次数减1,即数据元素个数为n-1,操作过程和第1趟类似,这样原来集合中次大值将被放在a[n-2]中。n-1趟结束时,原来集合的次小值被放在a[1]中,a[0]放最小元素。
2.时间复杂度:最好的情况(集合基本有序)O(n);最坏的情况(集合基本逆序)O(n^2); 平均O(n ^2) ;
3.空间复杂度:O(1);
4.稳定性:稳定
Java代码

public class BubbleSort 
{
	public static void bubblesort(int[] a) 
	{
		int n=a.length;
		int flag=0;
		for(int i=1;i<n-1;i++)//外层循环控制排序趟数,至少排一趟,i从1开始
		{
			flag=0;//设置标志变量,如果有哪一趟没有发生元素交换,说明已经全部有序,可以提前结束
			for(int j=0;j<n-i;j++)//内层循环控制每一趟排序多少次,每排一趟就会少排一个元素
			{
				if(a[j]>a[j+1])
				{
					int temp=a[j];
					a[j]=a[j+1];
					a[j+1]=temp;
					flag=1;
				}
			}
			if(flag==0)break;
		}
	}
	public static void main(String[] args)
	{
		int[] a= {4,2,5,7,3,1,8,6};
		bubblesort(a);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+" ");
			
		}
		System.out.print("好嗨呦");
	}
}
4.3.2快排

1.原理:快排是一种二叉树结构的交换排序法。设有n个数据待排序,存放在数组a中,low为数组的低端下标,high为高端下标,从a中任取一个元素(通常去a[low])为标准元素target,以target为标准调整a中其他各元素位置,使排在target之前的元素均小于target,排在target之后的元素均大于或等于target。这样一次排序过程结束后,target已经找好了它自己的位置,另一方面将a中元素以target为中心分成两个子数组,对两个子数组中元素进行类似的方法递归快速排序。递归出口是low>=high。
2.时间复杂度:与各次target选取有关,若每次选取的target都能均分子数组长度,这样的快排的过程就是一个完全二叉树结构。此时时间复杂度为O(nlbn);若集合正序或者反序,这样的快排过程就是一个二叉退化树,此时时间复杂度为O(nn);平均时间复杂度O(nlbn);
3.空间复杂度:快排需要用堆栈保存递归调用参数,最好情况O(lbn);最坏O(n
n);平均(lbn);
4.稳定性:不稳定。
Java代码

public class QuickSort 
{
	public static void quicksort(int[] a,int low,int high)
	{	
		int target=a[low];
		int i=low;
		int j=high;
		while(i<j)
		{	
			//找到右端第一个小于target的元素位置,放到空位置上
			while(i<j&&a[j]>target)j--;
			if(i<j)
				{
					a[i]=a[j];
					i++;
				}
			//找到左端第一个大于target的元素位置,放到空位置上
			while(i<j&&a[i]<target)i++;
			if(i<j)
			{
				a[j]=a[i];
				j--;
			}
		}
		//扫描完之后把target放到它最终应该在的位置上,不动了
		a[i]=target;
		if(low<i)quicksort(a,low,i-1);
		if(j<high)quicksort(a,j+1,high);
	}
	public static void main(String[] args)
	{
		int[] a= {4,2,5,7,3,1,8,6};
		quicksort(a,0,7);
		for(int i=0;i<a.length;i++)
		{
			System.out.print(a[i]+" ");
			
		}
		System.out.print("好嗨呦");
	}
}

4.4归并排序

1.基本思想:归并排序主要是二路归并。二路归并的基本思想是:数组a中放了n个元素,初始时把他们看做n个长度为1的有序子数组:a[0],a[1],a[2],…,a[n-1],然后从一个子数组开始,把相邻的子数组两两合并,得到n/2(向上取整)个长度为2的有序子数组,当n为偶数时得到:(a[0],a[1]),(a[2],a[3]),…,(a[n-2],a[n-1]).当n为奇数时得到(a[0],a[1]),(a[2],a[3]),…,(a[n-3],a[n-2]),(a[n-1]);对这些新的子数组再次两两归并,直到得到一个长度为n的数组为止。
2.时间复杂度为:O(nlbn)
3.空间复杂度:O(n);

5总结

1.不稳定的排序:快选希堆(快排、希尔排序、选择排序、堆排序);
2.对集合初始顺序比较敏感的排序:插入、希尔、冒泡、快排;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值