package com.wfy;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* 演示快速排序过程,每一次区间内排序的结果显示
* @author wfy
*
*/
public class ShowQuickSort2 extends Frame{
private static final long serialVersionUID = 741413479566665930L;
/**
* 保存随机生成的整数数组
*/
public int[] s;
/**
* 保存临时顺序的类
*/
private PrintTemp pt = new PrintTemp();
/**
* 当前数组中作为基准值的位置
*/
public int si;
/**
* 跟当前基准值做比较的数值位置
*/
public int sj;
/**
* 生成主窗口
*/
public void ShowFrame(){
this.setSize(640, 480);
setVisible(true);
setTitle("快速排序法-图形演示-wfy");
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void paint(Graphics g) {
drawBeforeSort(g);
pt.draw(g);
}
/**
* 在排序前重画当前数组并用颜色标注要比较的数
* 要知道当前基准数和被比较数在数组中的位置
* @param g
*/
public void drawBeforeSort(Graphics g){
Color c = g.getColor();
g.setColor(Color.black);
for(int i = 0; i < s.length; i++){
//如果当前位置是基准值,绿色显示
if(i == this.si){
g.setColor(Color.blue);
g.drawString(Integer.toString(s[i]), 26 * i + 20, 40);
g.drawRect(26 * i + 24, 50, 5, s[i]);
g.setColor(Color.black);
}else if(i == this.sj){
g.setColor(Color.red);
g.drawString(Integer.toString(s[i]), 26 * i + 20, 40);
g.drawRect(26 * i + 24, 50, 5, s[i]);
g.setColor(Color.black);
}else{
g.drawString(Integer.toString(s[i]), 26 * i + 20, 40);
g.drawRect(26 * i + 24, 50, 5, s[i]);
}
}
g.setColor(c);
}
/**
* 将每次的循环比较过程显示出来
* @param temp 当前正在排序的区间已经排好顺序的数值的临时存放处
* @param k 当前基准值在temp里的位置
* @param i 当前数组区间的起始坐标,跟j一起确定区间范围
* @param j 当前数组区间的终止坐标
* @param index 当前跟基准值比较的数字在数组中或temp中的位置,如果是排序前则表示在数组中的位置,排序后则表示在temp中的位置
* @param before 为真表示在排序前,已经选择好要用来比较的数字,为假表示已经跟选好的数比较完成
*/
public void draw(List<Integer> temp, int k, int i, int j, int index, boolean before){
if(temp == null && !before){
pt.j = 0;
repaint();
}
pt.list = temp;
/**
* 排序之前,参数index表示要比较的数在数组中的位置
*/
if(before){
this.si = i;
this.sj = index;
}else{
pt.i = i;
pt.j = j;
pt.index = index;
pt.k = k;
}
repaint();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 快速排序过程,针对数组的一段区间
* @param i 起始坐标
* @param j 终止坐标
*/
public void quickSort(int i, int j){
// k 是作为基准值拿出来与区间里的值比较的
int k = s[i];
// length 记录区间的总长度即元素个数
int length = j - i + 1;
// start 记录开始比较的坐标位置
int start = i++;
// temp 排序时会用来临时存放区间内数据
ArrayList<Integer> temp = new ArrayList<Integer>();
temp.add(k);
int left = 0; //记录temp的左边插入位置
int right = length - 1; //当temp的右边插入数据时自动减1
while(left < right){
int index = j;
/**
* 用颜色显示要比较的数
*/
draw(temp, left, start, start + length - 1, index, true);
//先跟右边的数比较
if(k > s[j]){
temp.add(left, s[j]); //把这个数插入到左边插入点
index = left;
left++;
}else{
temp.add(s[j]); //把这个数加入到基准值的后面
index = temp.size() - 1;
right--; //加到基准值的右边所以减1
}
/**
* 跟右边的数字比较后,显示出结果
*/
draw(temp, left, start, start + length - 1, index, false);
index = i;
draw(temp, left, start, start + length - 1, index, true);
/**
* 左右插入位置重叠说明所有数字都比较完成
* 这个时候k在temp里的位置就是left
*/
if(left == right){
break;
}
//再跟左边的数比较
if(k < s[i]){
temp.add(s[i]);
index = temp.size() - 1;
right--;
}else{
temp.add(left, s[i]);
index = left;
left++;
}
i++;
j--;
draw(temp, left, start, start + length-1, index, false);
}
/**
* 此时temp里的顺序就是本次排序后的顺序
* 这个方法保证了基准值左边的数值都比它小,右边的数值都比它大
* 然后按照这个顺序重写区间内的数字
*/
for(int t = 0; t < length; t++){
s[t + start] = temp.get(t);
}
temp = null;
draw(null, 0, 0, 0, 0, false);
/**
* 对temp左边,即基准值k的左边进行排序
* 这样分下去直到区间剩下两个数为止
*/
if(left > 1){
quickSort(start, start + left -1);
}
if(right + 1 < length -1){
quickSort(right + start + 1, start + length - 1);
}
}
public static void main(String args[]){
ShowQuickSort2 qs = new ShowQuickSort2();
qs.ShowFrame();
Random rd = new Random();
int[] s = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
int k = (int)((new Date().getTime() % 240));
for(int i = 0; i < s.length; i++){
s[i] = rd.nextInt(k);
System.out.print(s[i] + " ");
}
qs.s = s;
qs.quickSort(0, s.length - 1);
}
/**
* 用来显示排序过程
* @author wfy
*
*/
class PrintTemp{
/**
* 当前从区间中拿出来的数值的临时存放数组
*/
public List<Integer> list = new ArrayList<Integer>();
/**
* 区间范围的起始坐标
*/
int i;
/**
* 区间范围的终止坐标
*/
int j;
/**
* 基准值在list中的位置,主要是为了打印时用颜色
*/
int k;
/**
* list中新插入值的位置
*/
int index;
public void draw(Graphics g){
if(j == 0){
return;
}
Color c = g.getColor();
g.setColor(Color.black);
int length = list.size();
g.drawLine(26 * i + 18, 40, 26 * i + 18, 480);
g.drawLine(26 * j + 40, 40, 26 * j + 40, 480);
for(int st = 0; st < length; st++){
if(st == k){
g.setColor(Color.blue);
g.drawRect(26 * (st+i) + 24, 250, 5, list.get(st));
g.setColor(Color.black);
}else if(st == index){
g.setColor(Color.red);
g.drawRect(26 * (st+i) + 24, 250, 5, list.get(st));
g.setColor(Color.black);
}else{
g.drawRect(26 * (st+i) + 24, 250, 5, list.get(st));
}
}
g.setColor(c);
}
}
}