Java排序算法
1)分类:
1)插入排序(直接插入排序、希尔排序)
2)交换排序(冒泡排序、快速排序)
3)选择排序(直接选择排序、堆排序)
4)归并排序
5)分配排序(箱排序、基数排序)
所需辅助空间最多:归并排序
所需辅助空间最少:堆排序
平均速度最快:快速排序
不稳定:快速排序,希尔排序,堆排序。
1)选择排序算法的时候
1.数据的规模 ; 2.数据的类型 ; 3.数据已有的顺序
一般来说,当数据规模较小时,应选择直接插入排序或冒泡排序。任何排序算法在数据量小时基本体现不出来差距。 考虑数据的类型,比如如果全部是正整数,那么考虑使用桶排序为最优。 考虑数据已有顺序,快排是一种不稳定的排序(当然可以改进),对于大部分排好的数据,快排会浪费大量不必要的步骤。数据量极小,而起已经基本排好序,冒泡是最佳选择。我们说快排好,是指大量随机数据下,快排效果最理想。而不是所有情况。
3)总结:
——按平均的时间性能来分:
1)时间复杂度为O(nlogn)的方法有:快速排序、堆排序和归并排序,其中以快速排序为最好;
2)时间复杂度为O(n2)的有:直接插入排序、起泡排序和简单选择排序,其中以直接插入为最好,特 别是对那些对关键字近似有序的记录序列尤为如此;
3)时间复杂度为O(n)的排序方法只有,基数排序。
当待排记录序列按关键字顺序有序时,直接插入排序和起泡排序能达到O(n)的时间复杂度;而对于快速排序而言,这是最不好的情况,此时的时间性能蜕化为O(n2),因此是应该尽量避免的情况。简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。
——按平均的空间性能来分(指的是排序过程中所需的辅助空间大小):
1) 所有的简单排序方法(包括:直接插入、起泡和简单选择)和堆排序的空间复杂度为O(1);
2) 快速排序为O(logn ),为栈所需的辅助空间;
3) 归并排序所需辅助空间最多,其空间复杂度为O(n );
4)链式基数排序需附设队列首尾指针,则空间复杂度为O(rd )。
——排序方法的稳定性能:
1) 稳定的排序方法指的是,对于两个关键字相等的记录,它们在序列中的相对位置,在排序之前和 经过排序之后,没有改变。
2) 当对多关键字的记录序列进行LSD方法排序时,必须采用稳定的排序方法。
3) 对于不稳定的排序方法,只要能举出一个实例说明即可。
4) 快速排序,希尔排序和堆排序是不稳定的排序方法。
4)插入排序:
包括直接插入排序,希尔插入排序。
直接插入排序: 将一个记录插入到已经排序好的有序表中。
1, sorted数组的第0个位置没有放数据。
2,从sorted第二个数据开始处理:
如果该数据比它前面的数据要小,说明该数据要往前面移动。
首先将该数据备份放到 sorted的第0位置当哨兵。
然后将该数据前面那个数据后移。
然后往前搜索,找插入位置。
找到插入位置之后讲 第0位置的那个数据插入对应位置。
O(n*n), 当待排记录序列为正序时,时间复杂度提高至O(n)。
希尔排序(缩小增量排序 diminishing increment sort):先将整个待排记录序列分割成若干个子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行一次直接插入排序。
面试穿什么,这里找答案!
插入排序Java代码:
public class InsertionSort {
// 插入排序:直接插入排序 ,希尔排序
public void straightInsertionSort(double [] sorted){
int sortedLen= sorted.length;
for(int j=2;j<sortedLen;j++){
if(sorted[j]<sorted[j-1]){
sorted[0]= sorted[j];//先保存一下后面的那个
sorted[j]=sorted[j-1];// 前面的那个后移。
int insertPos=0;
for(int k=j-2;k>=0;k--){
if(sorted[k]>sorted[0]){
sorted[k+1]=sorted[k];
}else{
insertPos=k+1;
break;
}
}
sorted[insertPos]=sorted[0];
}
}
}
public void shellInertionSort(double [] sorted, int inc){
int sortedLen= sorted.length;
for(int j=inc+1;j<sortedLen;j++ ){
if(sorted[j]<sorted[j-inc]){
sorted[0]= sorted[j];//先保存一下后面的那个
int insertPos=j;
for(int k=j-inc;k>=0;k-=inc){
if(sorted[k]>sorted[0]){
sorted[k+inc]=sorted[k];
//数据结构课本上这个地方没有给出判读,出错:
if(k-inc<=0){
insertPos = k;
}
}else{
insertPos=k+inc;
break;
}
}
sorted[insertPos]=sorted[0];
}
}
}
public void shellInsertionSort(double [] sorted){
int[] incs={7,5,3,1};
int num= incs.length;
int inc=0;
for(int j=0;j<num;j++){
inc= incs[j];
shellInertionSort(sorted,inc);
}
}
public static void main(String[] args) {
Random random= new Random(6);
int arraysize= 21;
double [] sorted=new double[arraysize];
System.out.print("Before Sort:");
for(int j=1;j<arraysize;j++){
sorted[j]= (int)(random.nextDouble()* 100);
System.out.print((int)sorted[j]+" ");
}
System.out.println();
InsertionSort sorter=new InsertionSort();
// sorter.straightInsertionSort(sorted);
sorter.shellInsertionSort(sorted);
System.out.print("After Sort:");
for(int j=1;j<sorted.length;j++){
System.out.print((int)sorted[j]+" ");
}
System.out.println();
}
}
面试穿什么,这里找答案!
5)交换排序:
包括冒泡排序,快速排序。
冒泡排序法:该算法是专门针对已部分排序的数据进行排序的一种排序算法。如果在你的数据清单中只有一两个数据是乱序的话,用这种算法就是最快的排序算法。如果你的数据清单中的数据是随机排列的,那么这种方法就成了最慢的算法了。因此在使用这种算法之前一定要慎重。这种算法的核心思想是扫描数据清单,寻找出现乱序的两个相邻的项目。当找到这两个项目后,交换项目的位置然后继续扫描。重复上面的操作直到所有的项目都按顺序排好。
快速排序:通过一趟排序,将待排序记录分割成独立的两个部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。具体做法是:使用两个指针low,high, 初值分别设置为序列的头,和序列的尾,设置pivotkey为第一个记录,首先从high开始向前搜索第一个小于pivotkey的记录和pivotkey所在位置进行交换,然后从low开始向后搜索第一个大于pivotkey的记录和此时pivotkey所在位置进行交换,重复知道low=high了为止。
交换排序Java代码:
public class ExchangeSort {
public void BubbleExchangeSort(double [] sorted){
int sortedLen= sorted.length;
for(int j=sortedLen;j>0;j--){
int end= j;
for(int k=1;k<end-1;k++){
double tempB= sorted[k];
sorted[k]= sorted[k]<sorted[k+1]?
sorted[k]:sorted[k+1];
if(Math.abs(sorted[k]-tempB)>10e-6){
sorted[k+1]=tempB;
}
}
}
}
public void QuickExchangeSortBackTrack(double [] sorted,
int low,int high){
if(low<high){
int pivot= findPivot(sorted,low,high);
QuickExchangeSortBackTrack(sorted,low,pivot-1);
QuickExchangeSortBackTrack(sorted,pivot+1,high);
}
}
public int findPivot(double [] sorted, int low, int high){
sorted[0]= sorted[low];
while(low<high){
while(low<high && sorted[high]>= sorted[0])--high;
sorted[low]= sorted[high];
while(low<high && sorted[low]<=sorted[0])++low;
sorted[high]= sorted[low];
}
sorted[low]=sorted[0];
return low;
}
public static void main(String[] args) {
Random random= new Random(6);
int arraysize= 21;
double [] sorted=new double[arraysize];
System.out.print("Before Sort:");
for(int j=1;j<arraysize;j++){
sorted[j]= (int)(random.nextDouble()* 100);
System.out.print((int)sorted[j]+" ");
}
System.out.println();
ExchangeSort sorter=new ExchangeSort();
// sorter.BubbleExchangeSort(sorted);
sorter.QuickExchangeSortBackTrack(sorted, 1, arraysize-1);
System.out.print("After Sort:");
for(int j=1;j<sorted.length;j++){
System.out.print((int)sorted[j]+" ");
}
System.out.println();
}
}
6)选择排序:
分为直接选择排序, 堆排序
直接选择排序:第i次选取 i到array.Length-1中间最小的值放在i位置。
堆排序:首先,数组里面用层次遍历的顺序放一棵完全二叉树。从最后一个非终端结点往前面调整,直到到达根结点,这个时候除根节点以外的所有非终端节点都已经满足堆得条件了,于是需要调整根节点使得整个树满足堆得条件,于是从根节点开始,沿着它的儿子们往下面走(最大堆沿着最大的儿子走,最小堆沿着最小的儿子走)。 主程序里面,首先从最后一个非终端节点开始调整到根也调整完,形成一个heap, 然后将heap的根放到后面去(即:每次的树大小会变化,但是 root都是在1的位置,以方便计算儿子们的index,所以如果需要升序排列,则要逐步大顶堆。因为根节点被一个个放在后面去了。 降序排列则要建立小顶堆)
代码中的问题: 有时候第2个和第3个顺序不对(原因还没搞明白到底代码哪里有错)
选择排序Java代码:
public class SelectionSort {
public void straitSelectionSort(double [] sorted){
int sortedLen= sorted.length;
for(int j=1;j<sortedLen;j++){
int jMin= getMinIndex(sorted,j);
exchange(sorted,j,jMin);
}
}
public void exchange(double [] sorted,int i,int j){
int sortedLen= sorted.length;
if(i<sortedLen && j<sortedLen && i<j && i>=0 && j>=0){
double temp= sorted[i];
sorted[i]=sorted[j];
sorted[j]=temp;
}
}
public int getMinIndex(double [] sorted, int i){
int sortedLen= sorted.length;
int minJ=1;
double min= Double.MAX_VALUE;
for(int j=i;j<sortedLen;j++){
if(sorted[j]<min){
min= sorted[j];
minJ= j;
}
}
return minJ;
}
public void heapAdjust(double [] sorted,int start,int end){
if(start<end){
double temp= sorted[start];
// 这个地方j<end与课本不同,j<=end会报错:
for(int j=2*start;j<end;j *=2){
if(j+1<end && sorted[j]-sorted[j+1]>10e-6){
++j;
}
if(temp<=sorted[j]){
break;
}
sorted[start]=sorted[j];
start=j;
}
sorted[start]=temp;
}
}
public void heapSelectionSort(double [] sorted){
int sortedLen = sorted.length;
for(int i=sortedLen/2;i>0;i--){
heapAdjust(sorted,i,sortedLen);
}
for(int i=sortedLen;i>1;--i){
exchange(sorted,1,i);
heapAdjust(sorted,1,i-1);
}
}
public static void main(String [] args){
Random random= new Random(6);
int arraysize=9;
double [] sorted=new double[arraysize];
System.out.print("Before Sort:");
for(int j=1;j<arraysize;j++){
sorted[j]= (int)(random.nextDouble()* 100);
System.out.print((int)sorted[j]+" ");
}
System.out.println();
SelectionSort sorter=new SelectionSort();
// sorter.straitSelectionSort(sorted);
sorter.heapSelectionSort(sorted);
System.out.print("After Sort:");
for(int j=1;j<sorted.length;j++){
System.out.print((int)sorted[j]+" ");
}
System.out.println();
}
}
面试穿什么,这里找答案!
7)归并排序:
将两个或两个以上的有序表组合成一个新的有序表。归并排序要使用一个辅助数组,大小跟原数组相同,递归做法。每次将目标序列分解成两个序列,分别排序两个子序列之后,再将两个排序好的子序列merge到一起。
归并排序Java代码:
public class MergeSort {
private double[] bridge;//辅助数组
public void sort(double[] obj){
if (obj == null){
throw new NullPointerException("
The param can not be null!");
}
bridge = new double[obj.length]; // 初始化中间数组
mergeSort(obj, 0, obj.length - 1); // 归并排序
bridge = null;
}
private void mergeSort(double[] obj, int left, int right){
if (left < right){
int center = (left + right) / 2;
mergeSort(obj, left, center);
mergeSort(obj, center + 1, right);
merge(obj, left, center, right);
}
}
private void merge(double[] obj, int left,
int center, int right){
int mid = center + 1;
int third = left;
int tmp = left;
while (left <= center && mid <= right){
// 从两个数组中取出小的放入中间数组
if (obj[left]-obj[mid]<=10e-6){
bridge[third++] = obj[left++];
} else{
bridge[third++] = obj[mid++];
}
}
// 剩余部分依次置入中间数组
while (mid <= right){
bridge[third++] = obj[mid++];
}
while (left <= center){
bridge[third++] = obj[left++];
}
// 将中间数组的内容拷贝回原数组
(obj, tmp, right);
}
private void (double[] obj, int left, int right)
{
while (left <= right){
obj[left] = bridge[left];
left++;
}
}
public static void main(String[] args) {
Random random = new Random(6);
int arraysize = 10;
double[] sorted = new double[arraysize];
System.out.print("Before Sort:");
for (int j = 0; j < arraysize; j++) {
sorted[j] = (int) (random.nextDouble() * 100);
System.out.print((int) sorted[j] + " ");
}
System.out.println();
MergeSort sorter = new MergeSort();
sorter.sort(sorted);
System.out.print("After Sort:");
for (int j = 0; j < sorted.length; j++) {
System.out.print((int) sorted[j] + " ");
}
System.out.println();
}
}
面试穿什么,这里找答案!
8)基数排序:
使用10个辅助队列,假设最大数的数字位数为 x, 则一共做 x次,从个位数开始往前,以第i位数字的大小为依据,将数据放进辅助队列,搞定之后回收。下次再以高一位开始的数字位为依据。
以Vector作辅助队列,基数排序的Java代码:
public class RadixSort {
private int keyNum=-1;
private Vector<Vector<Double>> util;
public void distribute(double [] sorted, int nth){
if(nth<=keyNum && nth>0){
util=new Vector<Vector<Double>>();
for(int j=0;j<10;j++){
Vector <Double> temp= new Vector <Double>();
util.add(temp);
}
for(int j=0;j<sorted.length;j++){
int index= getNthDigit(sorted[j],nth);
util.get(index).add(sorted[j]);
}
}
}
public int getNthDigit(double num,int nth){
String nn= Integer.toString((int)num);
int len= nn.length();
if(len>=nth){
return Character.getNumericValue(nn.charAt(len-nth));
}else{
return 0;
}
}
public void collect(double [] sorted){
int k=0;
for(int j=0;j<10;j++){
int len= util.get(j).size();
if(len>0){
for(int i=0;i<len;i++){
sorted[k++]= util.get(j).get(i);
}
}
}
util=null;
}
public int getKeyNum(double [] sorted){
double max= Double.MIN_VALUE;
for(int j=0;j<sorted.length;j++){
if(sorted[j]>max){
max= sorted[j];
}
}
return Integer.toString((int)max).length();
}
public void radixSort(double [] sorted){
if(keyNum==-1){
keyNum= getKeyNum(sorted);
}
for(int i=1;i<=keyNum;i++){
distribute(sorted,i);
collect(sorted);
}
}
public static void main(String[] args) {
Random random = new Random(6);
int arraysize = 21;
double[] sorted = new double[arraysize];
System.out.print("Before Sort:");
for (int j = 0; j < arraysize; j++) {
sorted[j] = (int) (random.nextDouble() * 100);
System.out.print((int) sorted[j] + " ");
}
System.out.println();
RadixSort sorter = new RadixSort();
sorter.radixSort(sorted);
System.out.print("After Sort:");
for (int j = 0; j < sorted.length; j++) {
System.out.print((int) sorted[j] + " ");
}
System.out.println();
}
}
//而来
2. java编程题,对一组{23,55,-65,89,82,99,128}中的元素从小到大进行排序
1. 插入排序:插入排序基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
2. 选择排序:选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。
3. 冒泡排序:冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端。
4. 快速排序:快速排序(Quicksort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
5. 归并排序:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
6. 希尔排序:希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
你看这个链接,网页链接
希望可以帮到你,望采纳~
3. Java的几种常见排序
快速排序法、冒泡法、选择排序法、插入排序法
1.快速排序:
import java.util.Arrays;
public class Test2{
public static void main(String[] args){
int[] a={5,4,2,4,9,1};
Arrays.sort(a); //进行排序
for(int i: a){
System.out.print(i);
}
}
}
2.冒泡排序
public static int[] bubbleSort(int[] args){//冒泡排序算法
for(int i=0;i<args.length-1;i++){
for(int j=i+1;j<args.length;j++){
if (args[i]>args[j]){
int temp=args[i];
args[i]=args[j];
args[j]=temp;
}
}
}
return args;
}
3.选择排序
public static int[] selectSort(int[] args){//选择排序算法
for (int i=0;i<args.length-1 ;i++ ){
int min=i;
for (int j=i+1;j<args.length ;j++ ){
if (args[min]>args[j]){
min=j;
}
}
if (min!=i){
int temp=args[i];
args[i]=args[min];
args[min]=temp;
}
}
return args;
}
4.插入排序
public static int[] insertSort(int[] args){//插入排序算法
for(int i=1;i<args.length;i++){
for(int j=i;j>0;j--){
if (args[j]<args[j-1]){
int temp=args[j-1];
args[j-1]=args[j];
args[j]=temp;
}else break;
}
}
return args;
}
4. java里,几种排序方法各有什么优缺点
一、冒泡排序
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先比较 a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变。再比较a[3]与a[4],以此类推,最后比较a[n-1]与a[n]的值。这样处理一轮后,a[n]的值一定是这组数据中最大的。再对 a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的。再对a[1]~a[n-2]以相同方法处理一轮,以此类推。共处理n-1轮后a[1]、a[2]、……a[n]就以升序排列了。
优点:稳定;
缺点:慢,每次只能移动相邻两个数据。
二、选择排序
冒泡排序的改进版。
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
选择排序是不稳定的排序方法。
n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:
①初始状态:无序区为R[1..n],有序区为空。
②第1趟排序
在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
……
③第i趟排序
第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R(1≤i≤n- 1)。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。
优点:移动数据的次数已知(n-1次);
缺点:比较次数多。
三、插入排序
已知一组升序排列数据a[1]、a[2]、……a[n],一组无序数据b[1]、 b[2]、……b[m],需将二者合并成一个升序数列。首先比较b[1]与a[1]的值,若b[1]大于a[1],则跳过,比较b[1]与a[2]的值,若b[1]仍然大于a[2],则继续跳过,直到b[1]小于a数组中某一数据a[x],则将a[x]~a[n]分别向后移动一位,将b[1]插入到原来 a[x]的位置这就完成了b[1]的插入。b[2]~b[m]用相同方法插入。(若无数组a,可将b[1]当作n=1的数组a)
优点:稳定,快;
缺点:比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决这个问题。
三、缩小增量排序
由希尔在1959年提出,又称希尔排序(shell排序)。
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。发现当n不大时,插入排序的效果很好。首先取一增量d(d<n),将a[1]、a[1+d]、a[1+2d]……列为第一组,a[2]、a[2+d]、 a[2+2d]……列为第二组……,a[d]、a[2d]、a[3d]……列为最后一组以次类推,在各组内用插入排序,然后取d'<d,重复上述操作,直到d=1。
优点:快,数据移动少;
缺点:不稳定,d的取值是多少,应取多少个不同的值,都无法确切知道,只能凭经验来取。
四、快速排序
快速排序是目前已知的最快的排序方法。
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先任取数据 a[x]作为基准。比较a[x]与其它数据并排序,使a[x]排在数据的第k位,并且使a[1]~a[k-1]中的每一个数据<a[x],a[k+1]~a[n]中的每一个数据>a[x],然后采用分治的策略分别对a[1]~a[k-1]和a[k+1]~a[n] 两组数据进行快速排序。
优点:极快,数据移动少;
缺点:不稳定。
五、箱排序
已知一组无序正整数数据a[1]、a[2]、……a[n],需将其按升序排列。首先定义一个数组x[m],且m>=a[1]、a[2]、……a[n],接着循环n次,每次x[a]++.
优点:快,效率达到O(1)
缺点:数据范围必须为正整数并且比较小
六、归并排序
归并排序是多次将两个或两个以上的有序表合并成一个新的有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表。
归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比快速排序优势的地方.
5. java中冒泡排序算法的详细解答以及程序
实例说明
用冒泡排序方法对数组进行排序。
实例解析
交换排序的基本思想是两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。
应用交换排序基本思想的主要排序方法有冒泡排序和快速排序。
冒泡排序
将被排序的记录数组 R[1..n] 垂直排列,每个记录 R[i] 看做是重量为 R[i].key 的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组 R 。凡扫描到违反本原则的轻气泡,就使其向上“漂浮”。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
(1) 初始, R[1..n] 为无序区。
(2) 第一趟扫描,从无序区底部向上依次比较相邻的两个气泡的重量,若发现轻者在下、重者在上,则交换二者的位置。即依次比较 (R[n],R[n-1]) 、 (R[n-1],R[n-2]) 、 … 、 (R[2],R[1]); 对于每对气泡 (R[j+1],R[j]), 若 R[j+1].key<R[j].key, 则交换 R[j+1] 和 R[j] 的内容。
第一趟扫描完毕时,“最轻”的气泡就飘浮到该区间的顶部,即关键字最小的记录被放在最高位置 R[1] 上。
(3) 第二趟扫描,扫描 R[2..n]。扫描完毕时,“次轻”的气泡飘浮到 R[2] 的位置上 …… 最后,经过 n-1 趟扫描可得到有序区 R[1..n]。
注意:第 i 趟扫描时, R[1..i-1] 和 R[i..n] 分别为当前的有序区和无序区。扫描仍是从无序区底部向上直至该区顶部。扫描完毕时,该区中最轻气泡漂浮到顶部位置 R[i] 上,结果是 R[1..i] 变为新的有序区。
冒泡排序算法
因为每一趟排序都使有序区增加了一个气泡,在经过 n-1 趟排序之后,有序区中就有 n-1 个气泡,而无序区中气泡的重量总是大于等于有序区中气泡的重量,所以整个冒泡排序过程至多需要进行 n-1 趟排序。
若在某一趟排序中未发现气泡位置的交换,则说明待排序的无序区中所有气泡均满足轻者在上,重者在下的原则,因此,冒泡排序过程可在此趟排序后终止。为此,在下面给出的算法中,引入一个布尔量 exchange, 在每趟排序开始前,先将其置为 FALSE 。若排序过程中发生了交换,则将其置为 TRUE 。各趟排序结束时检查 exchange, 若未曾发生过交换则终止算法,不再进行下趟排序。
具体算法如下:
void BubbleSort(SeqList R){
//R(1..n) 是待排序的文件,采用自下向上扫描,对 R 做冒泡排序
int i,j;
Boolean exchange; // 交换标志
for(i=1;i<n;i++){ // 最多做 n-1 趟排序
exchange=FALSE; // 本趟排序开始前,交换标志应为假
for(j=n-1;j>=i;j--) // 对当前无序区 R[i..n] 自下向上扫描
if(R[j+1].key<R[j].key){ // 交换记录
R[0]=R[j+1]; //R[0] 不是哨兵,仅做暂存单元
R[j+1]=R[j];
R[j]=R[0];
exchange=TRUE; // 发生了交换,故将交换标志置为真
}
if(!exchange) // 本趟排序未发生交换,提前终止算法
return;
} //endfor( 外循环 )
}//BubbleSort
publicclassBubbleSort{
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
List<Integer>lstInteger=newArrayList<Integer>();
lstInteger.add(1);
lstInteger.add(1);
lstInteger.add(3);
lstInteger.add(2);
lstInteger.add(1);
for(inti=0;i<lstInteger.size();i++){
System.out.println(lstInteger.get(i));
}
System.out.println("排序之后-----------------");
lstInteger=sortList(lstInteger);
for(inti=0;i<lstInteger.size();i++){
System.out.println(lstInteger.get(i));
}
}
publicstaticList<Integer>sortList(List<Integer>lstInteger){
inti,j,m;
booleanblChange;
intn=lstInteger.size();
for(i=0;i<n;i++){
blChange=false;
for(j=n-1;j>i;j--){
if(lstInteger.get(j)<lstInteger.get(j-1)){
m=lstInteger.get(j-1);
lstInteger.set(j-1,lstInteger.get(j));
lstInteger.set(j,m);
blChange=true;
}
}
if(!blChange){
returnlstInteger;
}
}
returnlstInteger;
}
}
归纳注释
算法的最好时间复杂度:若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值,即C(min)=n-1,M(min)=0。冒泡排序最好的时间复杂度为O(n)。
算法的最坏时间复杂度:若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-1次关键字的比较(1<=i<=n-1),且每次比较都必须移动记录3次。在这种情况下,比较和移动次数均达到最大值,即C(max)=n(n-1)/2=O(n^2),M(max)=3n(n-1)/2=O(n^2)。冒泡排序的最坏时间复杂度为O(n^2)。
算法的平均时间复杂度为O(n^2)。虽然冒泡排序不一定要进行n-1趟,但由于它的记录移动次数较多,故平均时间性能比直接插入排序要差得多。
算法稳定性:冒泡排序是就地排序,且它是稳定的。
算法改进:上述的冒泡排序还可做如下的改进,①记住最后一次交换发生位置lastExchange的冒泡排序(该位置之前的相邻记录均已有序)。下一趟排序开始时,R[1..lastExchange-1]是有序区,R[lastExchange..n]是无序区。这样,一趟排序可能使当前有序区扩充多个记录,从而减少排序的趟数。②改变扫描方向的冒泡排序。冒泡排序具有不对称性。能一趟扫描完成排序的情况,只有最轻的气泡位于R[n]的位置,其余的气泡均已排好序,那么也只需一趟扫描就可以完成排序。如对初始关键字序列12、18、42、44、45、67、94、10就仅需一趟扫描。需要n-1趟扫描完成排序情况,当只有最重的气泡位于R[1]的位置,其余的气泡均已排好序时,则仍需做n-1趟扫描才能完成排序。比如对初始关键字序列:94、10、12、18、42、44、45、67就需7趟扫描。造成不对称性的原因是每趟扫描仅能使最重气泡“下沉”一个位置,因此使位于顶端的最重气泡下沉到底部时,需做n-1趟扫描。在排序过程中交替改变扫描方向,可改进不对称性
6. 请给出java几种排序方法
java常见的排序分为:
1 插入类排序
主要就是对于一个已经有序的序列中,插入一个新的记录。它包括:直接插入排序,折半插入排序和希尔排序
2 交换类排序
这类排序的核心就是每次比较都要“交换”,在每一趟排序都会两两发生一系列的“交换”排序,但是每一趟排序都会让一个记录排序到它的最终位置上。它包括:起泡排序,快速排序
3 选择类排序
每一趟排序都从一系列数据中选择一个最大或最小的记录,将它放置到第一个或最后一个为位置交换,只有在选择后才交换,比起交换类排序,减少了交换记录的时间。属于它的排序:简单选择排序,堆排序
4 归并类排序
将两个或两个以上的有序序列合并成一个新的序列
5 基数排序
主要基于多个关键字排序的。
下面针对上面所述的算法,讲解一些常用的java代码写的算法
二 插入类排序之直接插入排序
直接插入排序,一般对于已经有序的队列排序效果好。
基本思想:每趟将一个待排序的关键字按照大小插入到已经排序好的位置上。
算法思路,从后往前先找到要插入的位置,如果小于则就交换,将元素向后移动,将要插入数据插入该位置即可。时间复杂度为O(n2),空间复杂度为O(1)
package sort.algorithm;
public class DirectInsertSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2, 6, 10, 3, 9, 80, 1, 16, 27, 20 };
int temp, j;
for (int i = 1; i < data.length; i++) {
temp = data[i];
j = i - 1;
// 每次比较都是对于已经有序的
while (j >= 0 && data[j] > temp) {
data[j + 1] = data[j];
j--;
}
data[j + 1] = temp;
}
// 输出排序好的数据
for (int k = 0; k < data.length; k++) {
System.out.print(data[k] + " ");
}
}
}
三 插入类排序之折半插入排序(二分法排序)
条件:在一个已经有序的队列中,插入一个新的元素
折半插入排序记录的比较次数与初始序列无关
思想:折半插入就是首先将队列中取最小位置low和最大位置high,然后算出中间位置mid
将中间位置mid与待插入的数据data进行比较,
如果mid大于data,则就表示插入的数据在mid的左边,high=mid-1;
如果mid小于data,则就表示插入的数据在mid的右边,low=mid+1
最后整体进行右移操作。
时间复杂度O(n2),空间复杂度O(1)
package sort.algorithm;
//折半插入排序
public class HalfInsertSort {
public static void main(String[] args) {
int data[] = { 2, 6, 10, 3, 9, 80, 1, 16, 27, 20 };
// 存放临时要插入的元素数据
int temp;
int low, mid, high;
for (int i = 1; i < data.length; i++) {
temp = data[i];
// 在待插入排序的序号之前进行折半插入
low = 0;
high = i - 1;
while (low <= high) {
mid = (low + high) / 2;
if (temp < data[mid])
high = mid - 1;
else
// low=high的时候也就是找到了要插入的位置,
// 此时进入循环中,将low加1,则就是要插入的位置了
low = mid + 1;
}
// 找到了要插入的位置,从该位置一直到插入数据的位置之间数据向后移动
for (int j = i; j >= low + 1; j--)
data[j] = data[j - 1];
// low已经代表了要插入的位置了
data[low] = temp;
}
for (int k = 0; k < data.length; k++) {
System.out.print(data[k] + " ");
}
}
}
四 插入类排序之希尔排序
希尔排序,也叫缩小增量排序,目的就是尽可能的减少交换次数,每一个组内最后都是有序的。
将待续按照某一种规则分为几个子序列,不断缩小规则,最后用一个直接插入排序合成
空间复杂度为O(1),时间复杂度为O(nlog2n)
算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。当增量减到1时,进行直接插入排序后,排序完成。
package sort.algorithm;
public class ShellSort {
public static void main(String[] args) {
int a[] = { 1, 54, 6, 3, 78, 34, 12, 45, 56, 100 };
double d1 = a.length;
int temp = 0;
while (true)
{
//利用这个在将组内倍数减小
//这里依次为5,3,2,1
d1 = Math.ceil(d1 / 2);
//d为增量每个分组之间索引的增量
int d = (int) d1;
//每个分组内部排序
for (int x = 0; x < d; x++)
{
//组内利用直接插入排序
for (int i = x + d; i < a.length; i += d) {
int j = i - d;
temp = a[i];
for (; j >= 0 && temp < a[j]; j -= d) {
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
if (d == 1)
break;
}
for (int i = 0; i < a.length; i++)
System.out.print(a[i]+" ");
}
}
五 交换类排序之冒泡排序
交换类排序核心就是每次比较都要进行交换
冒泡排序:是一种交换排序
每一趟比较相邻的元素,较若大小不同则就会发生交换,每一趟排序都能将一个元素放到它最终的位置!每一趟就进行比较。
时间复杂度O(n2),空间复杂度O(1)
package sort.algorithm;
//冒泡排序:是一种交换排序
public class BubbleSort {
// 按照递增顺序排序
public static void main(String[] args) {
// TODO Auto-generated method stub
int data[] = { 2, 6, 10, 3, 9, 80, 1, 16, 27, 20, 13, 100, 37, 16 };
int temp = 0;
// 排序的比较趟数,每一趟都会将剩余最大数放在最后面
for (int i = 0; i < data.length - 1; i++) {
// 每一趟从开始进行比较,将该元素与其余的元素进行比较
for (int j = 0; j < data.length - 1; j++) {
if (data[j] > data[j + 1]) {
temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
}
}
}
for (int i = 0; i < data.length; i++)
System.out.print(data[i] + " ");
}
}
7. 数据结构 java开发中常用的排序算法有哪些
排序算法有很多,所以在特定情景中使用哪一种算法很重要。为了选择合适的算法,可以按照建议的顺序考虑以下标准:
(1)执行时间
(2)存储空间
(3)编程工作
对于数据量较小的情形,(1)(2)差别不大,主要考虑(3);而对于数据量大的,(1)为首要。
主要排序法有:
一、冒泡(Bubble)排序——相邻交换
二、选择排序——每次最小/大排在相应的位置
三、插入排序——将下一个插入已排好的序列中
四、壳(Shell)排序——缩小增量
五、归并排序
六、快速排序
七、堆排序
八、拓扑排序
一、冒泡(Bubble)排序
----------------------------------Code 从小到大排序n个数------------------------------------
void BubbleSortArray()
{
for(int i=1;i<n;i++)
{
for(int j=0;i<n-i;j++)
{
if(a[j]>a[j+1])//比较交换相邻元素
{
int temp;
temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;
}
}
}
}
-------------------------------------------------Code------------------------------------------------
效率 O(n²),适用于排序小列表。
二、选择排序
----------------------------------Code 从小到大排序n个数--------------------------------
void SelectSortArray()
{
int min_index;
for(int i=0;i<n-1;i++)
{
min_index=i;
for(int j=i+1;j<n;j++)//每次扫描选择最小项
if(arr[j]<arr[min_index]) min_index=j;
if(min_index!=i)//找到最小项交换,即将这一项移到列表中的正确位置
{
int temp;
temp=arr[i]; arr[i]=arr[min_index]; arr[min_index]=temp;
}
}
}
-------------------------------------------------Code-----------------------------------------
效率O(n²),适用于排序小的列表。
三、插入排序
--------------------------------------------Code 从小到大排序n个数-------------------------------------
void InsertSortArray()
{
for(int i=1;i<n;i++)//循环从第二个数组元素开始,因为arr[0]作为最初已排序部分
{
int temp=arr[i];//temp标记为未排序第一个元素
int j=i-1;
while (j>=0 && arr[j]>temp)/*将temp与已排序元素从小到大比较,寻找temp应插入的位置*/
{
arr[j+1]=arr[j];
j--;
}
arr[j+1]=temp;
}
}
------------------------------Code--------------------------------------------------------------
最佳效率O(n);最糟效率O(n²)与冒泡、选择相同,适用于排序小列表
若列表基本有序,则插入排序比冒泡、选择更有效率。
四、壳(Shell)排序——缩小增量排序
-------------------------------------Code 从小到大排序n个数-------------------------------------
void ShellSortArray()
{
for(int incr=3;incr<0;incr--)//增量递减,以增量3,2,1为例
{
for(int L=0;L<(n-1)/incr;L++)//重复分成的每个子列表
{
for(int i=L+incr;i<n;i+=incr)//对每个子列表应用插入排序
{
int temp=arr[i];
int j=i-incr;
while(j>=0&&arr[j]>temp)
{
arr[j+incr]=arr[j];
j-=incr;
}
arr[j+incr]=temp;
}
}
}
}
--------------------------------------Code-------------------------------------------
适用于排序小列表。
效率估计O(nlog2^n)~O(n^1.5),取决于增量值的最初大小。建议使用质数作为增量值,因为如果增量值是2的幂,则在下一个通道中会再次比较相同的元素。
壳(Shell)排序改进了插入排序,减少了比较的次数。是不稳定的排序,因为排序过程中元素可能会前后跳跃。
五、归并排序
----------------------------------------------Code 从小到大排序---------------------------------------
void MergeSort(int low,int high)
{
if(low>=high) return;//每个子列表中剩下一个元素时停止
else int mid=(low+high)/2;/*将列表划分成相等的两个子列表,若有奇数个元素,则在左边子列表大于右侧子列表*/
MergeSort(low,mid);//子列表进一步划分
MergeSort(mid+1,high);
int [] B=new int [high-low+1];//新建一个数组,用于存放归并的元素
for(int i=low,j=mid+1,k=low;i<=mid && j<=high;k++)/*两个子列表进行排序归并,直到两个子列表中的一个结束*/
{
if (arr[i]<=arr[j];)
{
B[k]=arr[i];
I++;
}
else
{ B[k]=arr[j]; j++; }
}
for( ;j<=high;j++,k++)//如果第二个子列表中仍然有元素,则追加到新列表
B[k]=arr[j];
for( ;i<=mid;i++,k++)//如果在第一个子列表中仍然有元素,则追加到新列表中
B[k]=arr[i];
for(int z=0;z<high-low+1;z++)//将排序的数组B的 所有元素复制到原始数组arr中
arr[z]=B[z];
}
-----------------------------------------------------Code---------------------------------------------------
效率O(nlogn),归并的最佳、平均和最糟用例效率之间没有差异。
适用于排序大列表,基于分治法。
六、快速排序
------------------------------------Code--------------------------------------------
/*快速排序的算法思想:选定一个枢纽元素,对待排序序列进行分割,分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。*/ void swap(int a,int b){int t;t =a ;a =b ;b =t ;}
int Partition(int [] arr,int low,int high)
{
int pivot=arr[low];//采用子序列的第一个元素作为枢纽元素
while (low < high)
{
//从后往前栽后半部分中寻找第一个小于枢纽元素的元素
while (low < high && arr[high] >= pivot)
{
--high;
}
//将这个比枢纽元素小的元素交换到前半部分
swap(arr[low], arr[high]);
//从前往后在前半部分中寻找第一个大于枢纽元素的元素
while (low <high &&arr [low ]<=pivot )
{
++low ;
}
swap (arr [low ],arr [high ]);//将这个枢纽元素大的元素交换到后半部分
}
return low ;//返回枢纽元素所在的位置
}
void QuickSort(int [] a,int low,int high)
{
if (low <high )
{
int n=Partition (a ,low ,high );
QuickSort (a ,low ,n );
QuickSort (a ,n +1,high );
}
}
----------------------------------------Code-------------------------------------
平均效率O(nlogn),适用于排序大列表。
此算法的总时间取决于枢纽值的位置;选择第一个元素作为枢纽,可能导致O(n²)的最糟用例效率。若数基本有序,效率反而最差。选项中间值作为枢纽,效率是O(nlogn)。
基于分治法。
七、堆排序
最大堆:后者任一非终端节点的关键字均大于或等于它的左、右孩子的关键字,此时位于堆顶的节点的关键字是整个序列中最大的。
思想:
(1)令i=l,并令temp= kl ;
(2)计算i的左孩子j=2i+1;
(3)若j<=n-1,则转(4),否则转(6);
(4)比较kj和kj+1,若kj+1>kj,则令j=j+1,否则j不变;
(5)比较temp和kj,若kj>temp,则令ki等于kj,并令i=j,j=2i+1,并转(3),否则转(6)
(6)令ki等于temp,结束。
-----------------------------------------Code---------------------------
void HeapSort(SeqIAst R)
{ //对R[1..n]进行堆排序,不妨用R[0]做暂存单元 int I; BuildHeap(R); //将R[1-n]建成初始堆for(i=n;i>1;i--) //对当前无序区R[1..i]进行堆排序,共做n-1趟。{ R[0]=R[1]; R[1]=R[i]; R[i]=R[0]; //将堆顶和堆中最后一个记录交换 Heapify(R,1,i-1); //将R[1..i-1]重新调整为堆,仅有R[1]可能违反堆性质 } } ---------------------------------------Code--------------------------------------
堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。
堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。 由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。 堆排序是就地排序,辅助空间为O(1), 它是不稳定的排序方法。
堆排序与直接插入排序的区别:
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
八、拓扑排序
例 :学生选修课排课先后顺序
拓扑排序:把有向图中各顶点按照它们相互之间的优先关系排列成一个线性序列的过程。
方法:
在有向图中选一个没有前驱的顶点且输出
从图中删除该顶点和所有以它为尾的弧
重复上述两步,直至全部顶点均已输出(拓扑排序成功),或者当图中不存在无前驱的顶点(图中有回路)为止。
---------------------------------------Code--------------------------------------
void TopologicalSort()/*输出拓扑排序函数。若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR*/
{
int indegree[M];
int i,k,j;
char n;
int count=0;
Stack thestack;
FindInDegree(G,indegree);//对各顶点求入度indegree[0....num]
InitStack(thestack);//初始化栈
for(i=0;i<G.num;i++)
Console.WriteLine("结点"+G.vertices[i].data+"的入度为"+indegree[i]);
for(i=0;i<G.num;i++)
{
if(indegree[i]==0)
Push(thestack.vertices[i]);
}
Console.Write("拓扑排序输出顺序为:");
while(thestack.Peek()!=null)
{
Pop(thestack.Peek());
j=locatevex(G,n);
if (j==-2)
{
Console.WriteLine("发生错误,程序结束。");
exit();
}
Console.Write(G.vertices[j].data);
count++;
for(p=G.vertices[j].firstarc;p!=NULL;p=p.nextarc)
{
k=p.adjvex;
if (!(--indegree[k]))
Push(G.vertices[k]);
}
}
if (count<G.num)
Cosole.WriteLine("该图有环,出现错误,无法排序。");
else
Console.WriteLine("排序成功。");
}
----------------------------------------Code--------------------------------------
算法的时间复杂度O(n+e)。
8. Java设计线性表排序算法
import java.util.Scanner;
import java.util.Arrays;
public class P
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
float[] A=new float[1],B=new float[1];
int alen=0,blen=0,i,j,k;
String line;
System.out.println("请输入线性表A的各元素,每行一个(输入#结束):");
while(true)
{
line=sc.nextLine();
if(line.equals("#"))
break;
A=Arrays.Of(A,++alen);
A[alen-1]=Float.parseFloat(line);
}
System.out.println("请输入线性表B的各元素,每行一个(输入#结束):");
while(true)
{
line=sc.nextLine();
if(line.equals("#"))
break;
B=Arrays.Of(B,++blen);
B[blen-1]=Float.parseFloat(line);
}
Arrays.sort(A);
Arrays.sort(B);
System.out.println("升序排序后,线性表A的各元素是:");
for(i=0;i<alen;i++)
{
System.out.print(A[i]+" ");
}
System.out.println();
System.out.println();
System.out.println("升序排序后,线性表B的各元素是:");
for(i=0;i<blen;i++)
{
System.out.print(B[i]+" ");
}
System.out.println();
System.out.println();
A=Arrays.Of(A,alen+blen);
for(i=0;i<blen;i++)
{
if(B[i]>=A[alen-1])
A[alen++]=B[i];
else
{
for(j=0;j<alen-1;j++)
{
if(B[i]<=A[j])
break;
}
for(k=alen-1;k>=j;k--)
{
A[k+1]=A[k];
}
A[j]=B[i];
alen++;
}
}
System.out.println("线性表B按顺序插入线性表A中后,线性表A的各元素是:");
for(i=0;i<alen;i++)
{
System.out.print(A[i]+" ");
}
sc.close();
}
}
9. JAVA 冒泡排序法的详细解释是什么
冒泡排序的英文Bubble Sort,是一种最基础的交换排序。
大家一定都喝过汽水,汽水中常常有许多小小的气泡,哗啦哗啦飘到上面来。这是因为组成小气泡的二氧化碳比水要轻,所以小气泡可以一点一点向上浮动。而我们的冒泡排序之所以叫做冒泡排序,正是因为这种排序算法的每一个元素都可以像小气泡一样,根据自身大小,一点一点向着数组的一侧移动。
冒泡排序算法的原理如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
具体如何来移动呢?让我们来看一个栗子:
希望对您有所帮助!~
10. 写一个简单的JAVA排序程序
// 排序
public class Array
{
public static int[] random(int n) //产生n个随机数,返回整型数组
{
if (n>0)
{
int table[] = new int[n];
for (int i=0; i<table.length; i++)
table[i] = (int)(Math.random()*100); //产生一个0~100之间的随机数
return table; //返回一个数组
}
return null;
}
public static void print(int[] table) //输出数组元素
{
if (table!=null)
for (int i=0; i<table.length; i++)
System.out.print(" "+table[i]);
System.out.println();
}
public static void insertSort(int[] table) //直接插入排序
{ //数组是引用类型,元素值将被改变
System.out.println("直接插入排序");
for (int i=1; i<table.length; i++) //n-1趟扫描
{
int temp=table[i], j; //每趟将table[i]插入到前面已排序的序列中
// System.out.print("移动");
for (j=i-1; j>-1 && temp<table[j]; j--) //将前面较大元素向后移动
{
// System.out.print(table[j]+", ");
table[j+1] = table[j];
}
table[j+1] = temp; //temp值到达插入位置
System.out.print("第"+i+"趟: ");
print(table);
}
}
public static void shellSort(int[] table) //希尔排序
{
System.out.println("希尔排序");
for (int delta=table.length/2; delta>0; delta/=2) //控制增量,增量减半,若干趟扫描
{
for (int i=delta; i<table.length; i++) //一趟中若干组,每个元素在自己所属组内进行直接插入排序
{
int temp = table[i]; //当前待插入元素
int j=i-delta; //相距delta远
while (j>=0 && temp<table[j]) //一组中前面较大的元素向后移动
{
table[j+delta] = table[j];
j-=delta; //继续与前面的元素比较
}
table[j+delta] = temp; //插入元素位置
}
System.out.print("delta="+delta+" ");
print(table);
}
}
private static void swap(int[] table, int i, int j) //交换数组中下标为i、j的元素
{
if (i>=0 && i<table.length && j>=0 && j<table.length && i!=j) //判断i、j是否越界
{
int temp = table[j];
table[j] = table[i];
table[i] = temp;
}
}
public static void bubbleSort(int[] table) //冒泡排序
{
System.out.println("冒泡排序");
boolean exchange=true; //是否交换的标记
for (int i=1; i<table.length && exchange; i++) //有交换时再进行下一趟,最多n-1趟
{
exchange=false; //假定元素未交换
for (int j=0; j<table.length-i; j++) //一次比较、交换
if (table[j]>table[j+1]) //反序时,交换
{
int temp = table[j];
table[j] = table[j+1];
table[j+1] = temp;
exchange=true; //有交换
}
System.out.print("第"+i+"趟: ");
print(table);
}
}
public static void quickSort(int[] table) //快速排序
{
quickSort(table, 0, table.length-1);
}
private static void quickSort(int[] table, int low, int high) //一趟快速排序,递归算法
{ //low、high指定序列的下界和上界
if (low<high) //序列有效
{
int i=low, j=high;
int vot=table[i]; //第一个值作为基准值
while (i!=j) //一趟排序
{
while (i<j && vot<=table[j]) //从后向前寻找较小值
j--;
if (i<j)
{
table[i]=table[j]; //较小元素向前移动
i++;
}
while (i<j && table[i]<vot) //从前向后寻找较大值
i++;
if (i<j)
{
table[j]=table[i]; //较大元素向后移动
j--;
}
}
table[i]=vot; //基准值的最终位置
System.out.print(low+".."+high+", vot="+vot+" ");
print(table);
quickSort(table, low, j-1); //前端子序列再排序
quickSort(table, i+1, high); //后端子序列再排序
}
}
public static void selectSort(int[] table) //直接选择排序
{
System.out.println("直接选择排序");
for (int i=0; i<table.length-1; i++) //n-1趟排序
{ //每趟在从table[i]开始的子序列中寻找最小元素
int min=i; //设第i个数据元素最小
for (int j=i+1; j<table.length; j++) //在子序列中查找最小值
if (table[j]<table[min])
min = j; //记住最小元素下标
if (min!=i) //将本趟最小元素交换到前边
{
int temp = table[i];
table[i] = table[min];
table[min] = temp;
}
System.out.print("第"+i+"趟: ");
print(table);
}
}
private static void sift(int[] table, int low, int high) //将以low为根的子树调整成最小堆
{ //low、high是序列下界和上界
int i=low; //子树的根
int j=2*i+1; //j为i结点的左孩子
int temp=table[i]; //获得第i个元素的值
while (j<=high) //沿较小值孩子结点向下筛选
{
if (j<high && table[j]>table[j+1]) //数组元素比较(改成<为最大堆)
j++; //j为左右孩子的较小者
if (temp>table[j]) //若父母结点值较大(改成<为最大堆)
{
table[i]=table[j]; //孩子结点中的较小值上移
i=j; //i、j向下一层
j=2*i+1;
}
else
j=high+1; //退出循环
}
table[i]=temp; //当前子树的原根值调整后的位置
System.out.print("sift "+low+".."+high+" ");
print(table);
}
public static void heapSort(int[] table)
{
System.out.println("堆排序");
int n=table.length;
for (int j=n/2-1; j>=0; j--) //创建最小堆
sift(table, j, n-1);
// System.out.println("最小堆? "+isMinHeap(table));
for (int j=n-1; j>0; j--) //每趟将最小值交换到后面,再调整成堆
{
int temp = table[0];
table[0] = table[j];
table[j] = temp;
sift(table, 0, j-1);
}
}
public static void mergeSort(int[] X) //归并排序
{
System.out.println("归并排序");
int n=1; //已排序的子序列长度,初值为1
int[] Y = new int[X.length]; //Y数组长度同X数组
do
{
mergepass(X, Y, n); //一趟归并,将X数组中各子序列归并到Y中
print(Y);
n*=2; //子序列长度加倍
if (n<X.length)
{
mergepass(Y, X, n); //将Y数组中各子序列再归并到X中
print(X);
n*=2;
}
} while (n<X.length);
}
private static void mergepass(int[] X, int[] Y, int n) //一趟归并
{
System.out.print("子序列长度n="+n+" ");
int i=0;
while (i<X.length-2*n+1)
{
merge(X,Y,i,i+n,n);
i += 2*n;
}
if (i+n<X.length)
merge(X,Y,i,i+n,n); //再一次归并
else
for (int j=i; j<X.length; j++) //将X剩余元素复制到Y中
Y[j]=X[j];
}
private static void merge(int[] X, int[] Y, int m, int r, int n) //一次归并
{
int i=m, j=r, k=m;
while (i<r && j<r+n && j<X.length) //将X中两个相邻子序列归并到Y中
if (X[i]<X[j]) //较小值复制到Y中
Y[k++]=X[i++];
else
Y[k++]=X[j++];
while (i<r) //将前一个子序列剩余元素复制到Y中
Y[k++]=X[i++];
while (j<r+n && j<X.length) //将后一个子序列剩余元素复制到Y中
Y[k++]=X[j++];
}
public static void main(String[] args)
{
// int[] table = {52,26,97,19,66,8,49};//Array.random(9);{49,65,13,81,76,97,38,49};////{85,12,36,24,47,30,53,91,76};//;//{4,5,8,1,2,7,3,6};// {32,26,87,72,26,17};//
int[] table = {13,27,38,49,97,76,49,81}; //最小堆
System.out.print("关键字序列: ");
Array.print(table);
// Array.insertSort(table);
// Array.shellSort(table);
// Array.bubbleSort(table);
// Array.quickSort(table);
// Array.selectSort(table);
// Array.heapSort(table);
// Array.mergeSort(table);
System.out.println("最小堆序列? "+Array.isMinHeap(table));
}
//第9章习题
public static boolean isMinHeap(int[] table) //判断一个数据序列是否为最小堆
{
if (table==null)
return false;
int i = table.length/2 -1; //最深一棵子树的根结点
while (i>=0)
{
int j=2*i+1; //左孩子
if (j<table.length)
if (table[i]>table[j])
return false;
else
if (j+1<table.length && table[i]>table[j+1]) //右孩子
return false;
i--;
}
return true;
}
}
/*
程序运行结果如下:
关键字序列: 32 26 87 72 26 17 8 40
直接插入排序
第1趟排序: 26 32 87 72 26 17 8 40
第2趟排序: 26 32 87 72 26 17 8 40
第3趟排序: 26 32 72 87 26 17 8 40
第4趟排序: 26 26 32 72 87 17 8 40 //排序算法稳定
第5趟排序: 17 26 26 32 72 87 8 40
第6趟排序: 8 17 26 26 32 72 87 40
第7趟排序: 8 17 26 26 32 40 72 87
关键字序列: 42 1 74 25 45 29 87 53
直接插入排序
第1趟排序: 1 42 74 25 45 29 87 53
第2趟排序: 1 42 74 25 45 29 87 53
第3趟排序: 1 25 42 74 45 29 87 53
第4趟排序: 1 25 42 45 74 29 87 53
第5趟排序: 1 25 29 42 45 74 87 53
第6趟排序: 1 25 29 42 45 74 87 53
第7趟排序: 1 25 29 42 45 53 74 87
关键字序列: 21 12 2 40 99 97 68 57
直接插入排序
第1趟排序: 12 21 2 40 99 97 68 57
第2趟排序: 2 12 21 40 99 97 68 57
第3趟排序: 2 12 21 40 99 97 68 57
第4趟排序: 2 12 21 40 99 97 68 57
第5趟排序: 2 12 21 40 97 99 68 57
第6趟排序: 2 12 21 40 68 97 99 57
第7趟排序: 2 12 21 40 57 68 97 99
关键字序列: 27 38 65 97 76 13 27 49 55 4
希尔排序
delta=5 13 27 49 55 4 27 38 65 97 76
delta=2 4 27 13 27 38 55 49 65 97 76
delta=1 4 13 27 27 38 49 55 65 76 97
关键字序列: 49 38 65 97 76 13 27 49 55 4 //严书
希尔排序
delta=5 13 27 49 55 4 49 38 65 97 76
delta=2 4 27 13 49 38 55 49 65 97 76 //与严书不同
delta=1 4 13 27 38 49 49 55 65 76 97
关键字序列: 65 34 25 87 12 38 56 46 14 77 92 23
希尔排序
delta=6 56 34 14 77 12 23 65 46 25 87 92 38
delta=3 56 12 14 65 34 23 77 46 25 87 92 38
delta=1 12 14 23 25 34 38 46 56 65 77 87 92
关键字序列: 84 12 43 62 86 7 90 91
希尔排序
delta=4 84 7 43 62 86 12 90 91
delta=2 43 7 84 12 86 62 90 91
delta=1 7 12 43 62 84 86 90 91
关键字序列: 32 26 87 72 26 17
冒泡排序
第1趟排序: 26 32 72 26 17 87
第2趟排序: 26 32 26 17 72 87
第3趟排序: 26 26 17 32 72 87
第4趟排序: 26 17 26 32 72 87
第5趟排序: 17 26 26 32 72 87
关键字序列: 1 2 3 4 5 6 7 8
冒泡排序
第1趟排序: 1 2 3 4 5 6 7 8
关键字序列: 1 3 2 4 5 8 6 7
冒泡排序
第1趟排序: 1 2 3 4 5 6 7 8
第2趟排序: 1 2 3 4 5 6 7 8
关键字序列: 4 5 8 1 2 7 3 6
冒泡排序
第1趟排序: 4 5 1 2 7 3 6 8
第2趟排序: 4 1 2 5 3 6 7 8
第3趟排序: 1 2 4 3 5 6 7 8
第4趟排序: 1 2 3 4 5 6 7 8
第5趟排序: 1 2 3 4 5 6 7 8
关键字序列: 38 26 97 19 66 1 5 49
0..7, vot=38 5 26 1 19 38 66 97 49
0..3, vot=5 1 5 26 19 38 66 97 49
2..3, vot=26 1 5 19 26 38 66 97 49
5..7, vot=66 1 5 19 26 38 49 66 97
关键字序列: 38 5 49 26 19 97 1 66
0..7, vot=38 1 5 19 26 38 97 49 66
0..3, vot=1 1 5 19 26 38 97 49 66
1..3, vot=5 1 5 19 26 38 97 49 66
2..3, vot=19 1 5 19 26 38 97 49 66
5..7, vot=97 1 5 19 26 38 66 49 97
5..6, vot=66 1 5 19 26 38 49 66 97
关键字序列: 49 38 65 97 76 13 27 49
0..7, vot=49 49 38 27 13 49 76 97 65
0..3, vot=49 13 38 27 49 49 76 97 65
0..2, vot=13 13 38 27 49 49 76 97 65
1..2, vot=38 13 27 38 49 49 76 97 65
5..7, vot=76 13 27 38 49 49 65 76 97
关键字序列: 27 38 65 97 76 13 27 49 55 4
low=0 high=9 vot=27 4 27 13 27 76 97 65 49 55 38
low=0 high=2 vot=4 4 27 13 27 76 97 65 49 55 38
low=1 high=2 vot=27 4 13 27 27 76 97 65 49 55 38
low=4 high=9 vot=76 4 13 27 27 38 55 65 49 76 97
low=4 high=7 vot=38 4 13 27 27 38 55 65 49 76 97
low=5 high=7 vot=55 4 13 27 27 38 49 55 65 76 97
关键字序列: 38 26 97 19 66 1 5 49
直接选择排序
第0趟排序: 1 26 97 19 66 38 5 49
第1趟排序: 1 5 97 19 66 38 26 49
第2趟排序: 1 5 19 97 66 38 26 49
第3趟排序: 1 5 19 26 66 38 97 49
第4趟排序: 1 5 19 26 38 66 97 49
第5趟排序: 1 5 19 26 38 49 97 66
第6趟排序: 1 5 19 26 38 49 66 97
最小堆
关键字序列: 81 49 76 27 97 38 49 13 65
sift 3..8 81 49 76 13 97 38 49 27 65
sift 2..8 81 49 38 13 97 76 49 27 65
sift 1..8 81 13 38 27 97 76 49 49 65
sift 0..8 13 27 38 49 97 76 49 81 65
13 27 38 49 97 76 49 81 65
sift 0..7 27 49 38 65 97 76 49 81 13
sift 0..6 38 49 49 65 97 76 81 27 13
sift 0..5 49 65 49 81 97 76 38 27 13
sift 0..4 49 65 76 81 97 49 38 27 13
sift 0..3 65 81 76 97 49 49 38 27 13
sift 0..2 76 81 97 65 49 49 38 27 13
sift 0..1 81 97 76 65 49 49 38 27 13
sift 0..0 97 81 76 65 49 49 38 27 13
最大堆
关键字序列: 49 65 13 81 76 27 97 38 49
sift 3..8 49 65 13 81 76 27 97 38 49
sift 2..8 49 65 97 81 76 27 13 38 49
sift 1..8 49 81 97 65 76 27 13 38 49
sift 0..8 97 81 49 65 76 27 13 38 49
97 81 49 65 76 27 13 38 49
sift 0..7 81 76 49 65 49 27 13 38 97
sift 0..6 76 65 49 38 49 27 13 81 97
sift 0..5 65 49 49 38 13 27 76 81 97
sift 0..4 49 38 49 27 13 65 76 81 97
sift 0..3 49 38 13 27 49 65 76 81 97
sift 0..2 38 27 13 49 49 65 76 81 97
sift 0..1 27 13 38 49 49 65 76 81 97
sift 0..0 13 27 38 49 49 65 76 81 97
关键字序列: 52 26 97 19 66 8 49
归并排序
子序列长度n=1 26 52 19 97 8 66 49
子序列长度n=2 19 26 52 97 8 49 66
子序列长度n=4 8 19 26 49 52 66 97
关键字序列: 13 27 38 49 97 76 49 81 65
最小堆序列? true
*/