`
gengu
  • 浏览: 86750 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

几种常见排序算法的实现[内部排序]

 
阅读更多

马上要找开始找工作了

 

抽点空对各种排序算法进行一下总结,随手从维基百科上搜索了一下。

 

排序算法大概分这么多种

稳定的

    冒泡排序(bubble sort) — O(n2)
    鸡尾酒排序 (Cocktail sort, 双向的冒泡排序) — O(n2)
    插入排序 (insertion sort)— O(n2)
    桶排序 (bucket sort)— O(n); 需要 O(k) 额外空间
    计数排序 (counting sort) — O(n+k); 需要 O(n+k) 额外空间
    合并排序 (merge sort)— O(n log n); 需要 O(n) 额外空间
    原地合并排序 — O(n2)
    二叉排序树排序 (Binary tree sort) — O(n log n)期望时间; O(n2)最坏时间; 需要 O(n) 额外空间
    鸽巢排序 (Pigeonhole sort) — O(n+k); 需要 O(k) 额外空间
    基数排序 (radix sort)— O(n·k); 需要 O(n) 额外空间
    Gnome 排序 — O(n2)
    图书馆排序 — O(n log n) with high probability, 需要 (1+ε)n 额外空间

[编辑] 不稳定

    选择排序 (selection sort)— O(n2)
    希尔排序 (shell sort)— O(n log n) 如果使用最佳的现在版本
    组合排序 — O(n log n)
    堆排序 (heapsort)— O(n log n)
    平滑排序 — O(n log n)
    快速排序 (quicksort)— O(n log n) 期望时间, O(n2) 最坏情况; 对于大的、乱数列表一般相信是最快的已知排序
    Introsort — O(n log n)
    Patience sorting — O(n log n + k) 最坏情况时间,需要 额外的 O(n + k) 空间,也需要找到最长的递增子串行(longest increasing subsequence)

[编辑] 不实用的排序算法

    Bogo排序 — O(n × n!) 期望时间,无穷的最坏情况。
    Stupid sort — O(n3); 递归版本需要 O(n2) 额外存储器
    珠排序(Bead sort) — O(n) or O(√n), 但需要特别的硬件
    Pancake sorting — O(n), 但需要特别的硬件

 

这里面有很多我听说过的,很多没听说过的,有些用过的,有些没用过,大部分用java实现了一遍,从中看一下他们的核心思想。

 

一:冒泡排序

大学课程里面第一个排序算法,它的基本思想是每一个不断的遍历数组,每次遍历总是把最大的那个数找出来放到数组的尾部。经过n轮遍历之后,就排序完成。

/**
	 * 实现冒泡泡排序
	 * @return void
	 * @param int[]
	 * 它的原理是每一次都把最大的数放到最后面
	 * */
	@SuppressWarnings("unused")
	private void bubbleSort(int[] array){
		
		//用于临时存数
		int temp = 0;
		for(int i = 1;i<array.length;i++){
			
			for(int j=0;j<array.length-i;j++){
				if(array[j]>array[j+1]){
					temp = array[j];
					array[j] = array[j+1];
					array[j+1] = temp;
				}
			}
		}
	}

 

二:插入排序

核心思想是:将一个数插入到一个有序表中,形成一个新的有序表

/**
	 * 实现插入排序
	 * 实现原理是将后面一个数都插入到前面已经排序好的序列中
	 * */
	@SuppressWarnings("unused")
	private void insertSort(int[] array){
		//从头开始遍历
		for(int i = 0;i<array.length;i++){
			int temp = array[i];
			int j = i;
			//确定每一个数的位置
			while(j>=0&&array[j]>temp){
				//如果有大的那么将前面的数向后面移动
				array[j+1] = array[j];
				j--;
			}
			array[j] = temp;
		}
	}

 

三:选择排序

核心思想是:遍历数组找出最大的那个数,然后插入到合适的正确的位置,这个跟冒泡很像

@SuppressWarnings("unused")
	public void chooseSort(int[] array){
		for(int i=0;i<array.length;i++){
		       //先给他一个小点的值
			int max = min;
			//存储那个最大数的位置
			int place = -1;
			for(int j=0;j<array.length-i;j++){
				//找到每一轮的最大的那个数和那个数的位置
				if(array[j]>max){
					max = array[j];
					place = j;
				}
			}
			//然后把它们插入到合适的位置
			array[place] = array[array.length-i-1];
			array[array.length-i] = max;
		}
	}

 

四:堆排序

这是所有排序中我觉得最复杂的一个,核心思想:其实也是找出最大值,然后也是插入到正确位置,只是找出最大值得办法是使用大顶堆,它的根就是最大值,然后与堆的最后一个节点交换,再进行向下堆调,成为一个新堆,这样重复,直到堆为空。

那么步骤是:1:建堆2:交换3:向下堆调

/**
	 * 实现堆排序
	 * 原理:先建立一个大顶堆,将最后一个元素与第一个元素调换然后向下堆调,依次下去就能得到一个有序数组了
	 * 堆:大顶堆
	 * */
	//建堆
	//向下堆调
	@SuppressWarnings("unused")
	private void shiftDown(int[] array,int st,int end){

		int parent = st;
		//这里之所以加1是因为数组的下标从0开始
		int lchild = 2*st+1;
		int rchild = 2*st+2;
		int max = 0,temp = 0;
		while(lchild<end){
			max = lchild;
			if(rchild<end){
				if(array[lchild]<array[rchild]){
					max=rchild;
				}
			}
			if(array[parent]<array[max]){
				//交换数据
				temp = array[parent];
				array[parent] = array[max];
				array[max] = temp;
				
				//进行下一次堆调当然也可以使用递归
				parent = max;
				lchild = 2*parent+1;
				rchild = 2*parent+2;
			}
			else{break;}
		}
	}
	
	//创建堆
	private void createHeap(int[] array){
		
		for(int i=array.length/2-1;i>=0;i--){
			shiftDown(array,i,array.length);
		}
		print(array);
	}
	
	//这里是堆排序的实现
	public void heapSort(int[] array){
		createHeap(array);
		
		int temp = 0;
		for(int i=1;i<array.length;i++){
			
			temp = array[0];
			array[0] = array[array.length-i];
			array[array.length-i] = temp;
			
			shiftDown(array,0, array.length-i-1);
		}
		
	}

 

五:计数排序

核心思想:对于特定元素x来说,如果确定了序列中比其小的元素的个数。那么就能确定x的位置了,a数组中的数都为非负整数。如果有负数,则因该加上一个数,使其为正。

在这个程序中我们创建了两个大数组,一个用于计数,一个用于临时存储。

/**
	 * 计数排序
	 * 对于特定的元素来说,如果确定了序列中比其小的元素的个数,那么就能确定这个元素的位置了
	 * */
	public void countingSort(int[] array){
		//int数组赋值为0
		int[] count = new int[10000];
		int[] copy = new int[10000];
		
		//给count数组赋值
		for(int i=0;i<array.length;i++){
			count[array[i]]=1;
		}
		//得到比count[i]小的数只是用了一种特殊的方式
		//在纸上画一下就知道了
		for(int i=1;i<10000;i++){
			count[i] = count[i]+count[i-1];
		}
		//在合适的地方放上合适的数
		for(int i=array.length-1;i>=0;i--){
			copy[count[array[i]]-1] = array[i];
		}
		//再把排序好的数据放好
		for(int i=0;i<array.length;i++){
			array[i] = copy[i];
		}
	}

 

六:归并排序

归并排序使用了分治的思想,将一个大的排序分为若干个小的排序

归并排序分为自顶向下,自底向上的排序,当然我们熟知的是自顶向下

后者与前者的区别主要在于后者是合并的过程,而前者是划分的过程,前者与快速排序的思想很相像。下面来看一下它的实现过程。

/**
	 * 合并数组的两段
	 * @param array int[]
	 * @param start 
	 * @param end
	 * @param mid
	 * 将两个排序好的数组合并成一个
	 * */
	public void merge(int[] array,int start,int mid,int end){
		
		//一个辅助数组
		int[] comment = new int[10000];
		int s = start,m = mid,index=start;
		while(s<mid&&m<end){
			if(array[s]<=array[m]){
				comment[index] = array[s];
				s++;
			}
			else {
				comment[index] = array[m];
				m++;
			}
			index++;
		}
		//如果前面这个数组被索引完毕
		if(s == mid){
			
			while(m<end){
				comment[index++] = array[m++];
			}
		}else{
			//System.out.println("s=="+s);
			while(s<end){
				comment[index++] = array[s++];
			}
		}
		
		for(int i = start;i<end;i++){
			array[i] = comment[i];
		}
	}
	
	//实现mergeSort归并排序
	public void mergeSort(int[] array){
		int t = 1;
		int start = 0;
		int i = 0;
		
		while(t<=array.length){
			start = t;
			t = 2*start;
			i = 0;
			while((i+t)<=array.length){
				merge(array, i, i+start, i+t);
				i = i+t;
			}
			print(array);
			if(i+start<array.length){
				merge(array, i, i+start, array.length);
			}
		}
	}
	
	
        //这里实现的是自顶向上的排序
	public void mergeSort1(int[] array, int p1, int p3) {
			if((p3-p1) <= 1) return; //判断是否不需要继续递归

			int p2 = (p3 + p1)/2; //计算中间位置p2

			mergeSort1(array,p1,p2); //将p1 ~ p2之间递归排序
			mergeSort1(array,p2,p3); //将p2 ~ p3之间递归排序 
			
			merge(array,p1,p2,p3); //合并p1~p2,p2~p3
	}

 

七:快速排序

快速排序是一个也是典型的分治

/**
	 * 这里是最经典也用的最多的快速排序
	 * 与merge的不同在于它是一个划分的过程
 * */
	private int split(int[] array,int left,int right){
		int key = array[left];
		int temp = 0;
		int low = left+1;
		int high = right;
		while(low<high){
			if(array[low]<=key) low++;
			else if(array[high]>=key) high--;
			else {
				temp = array[low];
				array[low] = array[high];
				array[high] = temp;
				
			}
		}
		array[left] = array[--low];
		array[low] =key;
		
		return low;
		
	}
	//实现快速排序
	public void quickSort(int[] array,int low,int right){
		int devide = 0;
		if(low<right){
			devide = split(array, low, right);
			System.out.println(devide);
			print(array);
			quickSort(array, low, devide-1);
			quickSort(array, devide+1, right);
		}
	}
 

八:希尔排序

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

	/**
	 * 希尔排序
	 * h = h*3+1.初始 h=1 
	 * */
	
	public void shellSort(int[] array){
		 int h = 1;
		    while(h<array.length)
		        h = h*3+1;
		    h = (h-1)/3;
		    while(h>=1)
		    {
		        for(int i=h;i<array.length;i++)
		        {
		           int j = i-h;
		           int key = array[i];
		           while(j>=0&&array[j]>key)
		           {
		                array[j+h] = array[j];
		                j-=h;     
		           } 
		           j+=h;
		           array[j]=key; 
		        }
		        h=(h-1)/3; 
		    }
	}

 

九:基数排序

这个描述起来比较复杂,算是归纳法的一种吧。实现方式就是一下的,没有这么写注释,就是按照十进制位来排序,比如先第一位排序,然后按照第二位,直到最高位,需要比较大的空间开销。

public  void radixSort(int[] number, int d) {
		int k=0;
		int n=1;
		int m=1;
		int[][] temp = new int[number.length][number.length];
		int[] order = new int[number.length];
		while(m <= d) {
			for(int i = 0; i < number.length; i++) {
				int lsd = ((number[i] / n) % 10);
				temp[lsd][order[lsd]] = number[i];
				order[lsd]++;
			}
			for(int i = 0; i < d; i++) {
				if(order[i] != 0)
					for(int j = 0; j < order[i]; j++) {
						number[k] = temp[i][j];
						k++;
					}
				order[i] = 0;
			}
			n *= 10;
			k = 0;
			m++;
		}
	}
 

马上要找工作了,以上的排序算法在大学多多少少都接触过,但很长时间没有用了,有的就忘记了,现在把它们整理一遍。只是对一些常见的排序算法的一个实现,没有仔细的研究各个算法的时间复杂度空间复杂度。

 

 

 

 

2
0
分享到:
评论

相关推荐

    几种常见排序算法实现

    几种常见排序 基于比较的排序算法: 下界是 nlgn 1.1 SelectionSort:每次选出最下的元素,放在当前循环最左边的位置。 1.2 BubbleSort:每次比较相邻的两个数,使得最大的数像气泡一样冒到最右边。 1. 3 Insertion...

    几种常见排序算法实例

    本文将详细解析标题中提及的五种排序算法:位与、选择、冒泡、插入以及qsort,并结合在VC6.0环境下进行编译实践的情况。 1. **位与排序**: 位与操作符(`&`)在某些特定场景下可用于排序,例如在整数数组中,通过...

    几种常见排序算法代码

    几种常见的排序算法是编程领域中基础且重要的知识点,它们各自有不同的特点和适用场景。本文将详细介绍这些算法,并分析其效率。 一、冒泡排序 冒泡排序是一种简单的排序算法,通过不断交换相邻的两个元素来逐步...

    几种常见排序算法JAVA实现.pdf

    几种常见排序算法JAVA实现.pdf

    设计一个测试程序比较几种内部排序算法的关键字比较次数和移动次数以取得直观感受。

    设计一个测试程序比较几种内部排序算法的关键字比较次数和移动次数以取得直观感受。 在本文中,我们将设计一个测试程序比较几种内部排序算法的关键字比较次数和移动次数,以取得直观感受。内部排序算法是指在内存中...

    几种常见排序算法的实现

    本文将深入探讨六种常见的排序算法:选择排序、插入排序、冒泡排序、希尔排序、快速排序以及归并排序,它们都是编程实践中不可或缺的基础知识。 1. **选择排序(Selection Sort)**: 选择排序的工作原理是每一次...

    几种常用排序算法的C语言实现

    一些常用排序算法的C语言实现,包括直接选择排序,希尔排序,直接插入排序,快速排序,归并排序,冒泡排序,堆排序

    用Java实现几种常见的排序算法

    根据提供的文件信息,本文将详细介绍如何使用Java语言来实现几种常见的排序算法,包括插入排序(Insert Sort)、冒泡排序(Bubble Sort)、选择排序(Selection Sort)以及希尔排序(Shell Sort)。这些排序算法在...

    几种内部排序算法总结

    ### 几种内部排序算法总结 #### 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法,它重复地遍历待排序的数列,依次比较相邻的两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的,...

    几种常见排序算法(JAVA实现).pdf

    几种常见排序算法(JAVA实现).pdf

    数据结构中几种常见的排序算法之比较

    数据结构中几种常见的排序算法之比较,比较常见的冒泡排序、快速排序等

    最常见的几种排序算法,来看看

    这里我们将深入探讨几种最常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序以及归并排序。 1. 冒泡排序(Bubble Sort) 冒泡排序是最基础的排序算法之一,它通过不断地比较相邻元素并交换位置来实现...

    内部排序算法比较 课程设计

    【内部排序算法比较课程设计】主要关注的是对六种经典的内部排序算法的性能对比,包括起泡排序、直接插入排序、简单选择排序、快速排序、希尔排序和堆排序。这些算法是计算机科学中用于对数据进行排序的基础工具,各...

    7.1_内部排序算法排序.CPP

    1、常见排序算法实现(1-6选择几个算法练习) 1)问题描述:输入一组关键字序列分别实现下列排序。 (1)实现简单选择排序、直接插入排序和冒泡排序。 (2)实现希尔排序算法。 (3)实现折半插入排序。 ...

    java实现数据结构常见排序算法及详解

    ### Java 实现数据结构常见排序算法及详解 #### 排序算法概述 排序算法是计算机科学中的基础概念之一,主要用于将一系列数据按照特定规则进行排列。根据数据处理方式的不同,排序算法大致分为两大类:比较排序与非...

    内部排序算法的性能分析

    本项目针对内部排序算法进行了性能分析,通过设计一个测试程序,对比了几种常见内部排序算法的关键字比较次数和移动次数,以帮助我们更直观地理解不同算法的效率差异。以下是关于内部排序算法的一些关键知识点: 1....

    几种经典排序算法的实现比较

    这四种排序算法各有特点,适用于不同的场景,对于大数据处理时的速度比较尤其关键。 1. **快速排序**: 快速排序由C.A.R. Hoare在1960年提出,是一种采用分治策略的排序算法。其基本思想是选取一个基准元素,将...

    各种排序算法比较(java实现)

    本文将详细探讨标题所提及的几种排序算法:合并排序、插入排序、希尔排序、快速排序、冒泡排序以及桶排序,并结合Java语言的实现进行解析。 1. **合并排序(Merge Sort)**: 合并排序是一种基于分治策略的排序算法...

Global site tag (gtag.js) - Google Analytics