一、前言:
这是怀化学院的:Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究,问题基本解决,若有bug欢迎下方评论提出意见,我会第一时间改进代码,谢谢!) 后面其他编程题只要我写完,并成功实现,会陆续更新,记得三连哈哈! 所有答案供参考,不是标准答案,是博主自己研究的写法。(这一个题书上也有现成类似的代码,重要的是理解它的算法原理!)
二、题目要求如下:
(第 18 题) 快速排序(难度系数85)
快速排序的核心操作是划分,通过某个数据将原来排序表分成两部分,前面部分比该数小,后面数据比该数据大或相等,该位置就为某数据排序后的位置,即该数据完成排序。如果定义一个排序表的划分方法为:
int partition(int[] R,int low,int high); 其中,low,high表示将数据R的第low个数据到high个数据进行划分,返回到整数为划分后到支点存储的位置;快速排序在查找分支点位置的方法有多种,本题目的排序过程中,首先从右向左移动,搜索小于分支记录的第一个元素,再从左向右移动,搜索大于分支记录的第一个元素,交互该两个记录值,继续搜索,直到两个搜索点交汇,如果交汇点记录与分支记录相等,分支记录与交汇点数据不交换,分支位置为交汇位置; 完成划分方法后,通过递归调用完成快速排序:
void QuickSort(int[] R,int s,int t){
if(s<t) {
int i=partition(R,s,t);
QuickSort(R,s,i-1);
QuickSort(R,i+1,t);
}
}
建议每次划分选择第一个元素为支点记录进行编程。给你到问题是,将标准输入的n个整数采用快速排序,并需要显示出每次划分分支点存储的位置,第一个数为0,分支点的输出顺序按照程序递归产生的分支点的先后进行输出,并完成该数据的排序。
输入:标准输入,输入的第一行为整数的个数n值,第二行为n个整数,每个整数之间为一个空格。
输出:标准输出,输出的第一行依次输出排序过程中使用的支点位置,每个输出数据之间使用一个空格隔开,第二行输出排序后的序列,每个输出数据之间使用一个空格隔开。
输入样例:
14
39 80 76 41 13 29 50 78 30 11 100 7 41 86
输出样例:
5 3 2 1 8 6 9 13 12 10
7 11 13 29 30 39 41 41 50 76 78 80 86 100
补充:题目意思一定要深度揣摩一下,没有提示就得自己根据它题目给的输入输出来推一下原理了,不然就是盲目下手出错很多!这个题它给出了递归调用的方法,那只要研究怎么进行快速排序就行,然后注意它的题目要求。
三、代码实现: (代码的做题原理全部在代码注释中,若还有疑问也可以翻数据结构书关于快速排序的基本原理的内容)
补充:应该当你放到考试系统里检测代码是否正确时,请把所有的代码注释去掉!不过是自己的编译器应该没问题的
(1)为了方便,就没有去专门写一个快速排序类然后在测试类去调用它的排序方法,而是全部写在一个类里,它里面的排序方法,以及主方法都在该类中。
package com.fs.sort;
import java.util.Scanner;
public class Main {
public void quickSort(int[]data){
//从0开始,到最后数组的最后一个数的下标
quickSort(data,0,data.length-1);
}
//low:意思是拿来比较的基值的下标,high:表示从右往左遍历与基值比较大小
public void quickSort(int[]data,int low,int high){
//由题目给的方法:只要满足low小于high那就要继续划分
//每次产生的分支点输出后并返回过来继续按照分支点分成两个部分来快速排序
if(low<high) {
int branch_point = point(data, low, high);
quickSort(data,low,branch_point-1);
quickSort(data,branch_point+1,high);
}
}
//这里是用来快速排序和找到交汇点并返回分支点的位置
public int point(int[]data,int low01,int high01) {
//每次快速排序的基准值(也就是对比值,默认每次都是第一个元素)
int base = low01; //除了刚开始的默认值下标会是0,其他进行第n次拆分的会变化
//默认从左边向右边遍历时第一个值的下标(当然是基值下标开始:low那个开始)
int i = low01;
//默认从右边向左边遍历时最后一个值的下标(当然是从下标:data.length-1那里开始)
int j = high01;
//从左向后遍历 与从右向前遍历时只要下标不自增到相等,就进行他们各自当前位置的下标值与基值比较
//从左向右:只要保证(i<j),且data[i]<=data[base](也就是比基值小或相等)i++,向后移动。且当i,j都固定时(而且i<j)要交换i与j位置的元素,这样两边才能继续向中间遍历,直到i==j为止
//从右向右:只要保证(i<j),且data[j]>=data[base](也就是比基值大或相等)j--,向前移动。且当i,j都固定时(而且i<j)要交换i与j位置的元素,这样两边才能继续向中间遍历,直到i==j为止
//这样写的作用就是把一部分大的数值放后面,小的数值放前面
int temp;
while (i < j) {
while ((j > i) && (data[j] >= data[base])) {
--j;
}
while ((i < j) && data[i] <= data[base]) {
++i;
}
//每次i,j自增完(只要还满足i<j)都要把那他们互相交换位置,因为这是把大的值放到后面,小的值放在前面
if (i < j) {
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
//当i与j自增到退出前面循环时,也就是它们在同一位置时,判断这个位置下标的值与基值比较,如果大于基值不用交换,小于基值:就把基值的位置与该(i==j)下标的位置交换
if (data[base] > data[i]) {
temp = data[base];
data[base] = data[i];
data[i] = temp;
}
//题目要求输出的每次的分支点位置:
System.out.print(i + " ");
return i;
}
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
int n=sc.nextInt(); //所要排序的整数个数
int []data=new int[n];
for(int i=0;i<n;i++){
data[i]=sc.nextInt();
}
Main m = new Main();
m.quickSort(data);
System.out.println(); //控制在下一行
for(int k=0;k<n;k++){
System.out.print(data[k]+" ");
}
}
}
四、代码测试运行结果:
<1>题目上的测试输入样例:
<2> 我就用书上的测试样例: