预警:本节使用java的JFrame为例子,请对该场景不适的同学退场。
JFrame
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(() -> { // 将创建窗口过程放进**创建分发线程**中,这样当窗口越来越大时,可以避免一些问题
JFrame frame = new JFrame("Welcome");
frame.setSize(500, 500);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
Graphics2D
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import javax.swing.*;
public class AlgoFrame extends JFrame{
private int canvasWidth;
private int canvasHeight;
public AlgoFrame(String title, int canvasWidth, int canvasHeight){
super(title);
this.canvasWidth = canvasWidth;
this.canvasHeight = canvasHeight;
AlgoCanvas canvas = new AlgoCanvas();
// 视口大小根据画布大小调整
setContentPane(canvas);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
public AlgoFrame(String title){
this(title, 1024, 768);
}
public int getCanvasWidth(){return canvasWidth;}
public int getCanvasHeight(){return canvasHeight;}
// data
int[] money;
public void render(int[] money){
this.money = money;
repaint();
}
private class AlgoCanvas extends JPanel{
public AlgoCanvas(){
// 双缓存
super(true);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// 抗锯齿
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.addRenderingHints(hints);
// 具体绘制
AlgoVisHelper.setColor(g2d, AlgoVisHelper.Blue);
int w = canvasWidth / money.length;
for(int i = 0 ; i < money.length ; i ++)
AlgoVisHelper.fillRectangle(g2d,
i*w+1, canvasHeight-money[i], w-1, money[i]);
}
/**
* 返回画布大小(自动调用)
* @return
*/
@Override
public Dimension getPreferredSize(){
return new Dimension(canvasWidth, canvasHeight);
}
}
}
助手类
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.lang.InterruptedException;
public class AlgoVisHelper {
private AlgoVisHelper(){}
public static final Color Red = new Color(0xF44336);
public static final Color Pink = new Color(0xE91E63);
public static final Color Purple = new Color(0x9C27B0);
public static final Color DeepPurple = new Color(0x673AB7);
public static final Color Indigo = new Color(0x3F51B5);
public static final Color Blue = new Color(0x2196F3);
public static final Color LightBlue = new Color(0x03A9F4);
public static final Color Cyan = new Color(0x00BCD4);
public static final Color Teal = new Color(0x009688);
public static final Color Green = new Color(0x4CAF50);
public static final Color LightGreen = new Color(0x8BC34A);
public static final Color Lime = new Color(0xCDDC39);
public static final Color Yellow = new Color(0xFFEB3B);
public static final Color Amber = new Color(0xFFC107);
public static final Color Orange = new Color(0xFF9800);
public static final Color DeepOrange = new Color(0xFF5722);
public static final Color Brown = new Color(0x795548);
public static final Color Grey = new Color(0x9E9E9E);
public static final Color BlueGrey = new Color(0x607D8B);
public static final Color Black = new Color(0x000000);
public static final Color White = new Color(0xFFFFFF);
public static void strokeCircle(Graphics2D g, int x, int y, int r){
Ellipse2D circle = new Ellipse2D.Double(x-r, y-r, 2*r, 2*r);
g.draw(circle);
}
public static void fillCircle(Graphics2D g, int x, int y, int r){
Ellipse2D circle = new Ellipse2D.Double(x-r, y-r, 2*r, 2*r);
g.fill(circle);
}
public static void strokeRectangle(Graphics2D g, int x, int y, int w, int h){
Rectangle2D rectangle = new Rectangle2D.Double(x, y, w, h);
g.draw(rectangle);
}
public static void fillRectangle(Graphics2D g, int x, int y, int w, int h){
Rectangle2D rectangle = new Rectangle2D.Double(x, y, w, h);
g.fill(rectangle);
}
public static void setColor(Graphics2D g, Color color){
g.setColor(color);
}
public static void setStrokeWidth(Graphics2D g, int w){
int strokeWidth = w;
g.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
}
public static void pause(int t) {
try {
Thread.sleep(t);
}
catch (InterruptedException e) {
System.out.println("Error sleeping");
}
}
public static void putImage(Graphics2D g, int x, int y, String imageURL){
ImageIcon icon = new ImageIcon(imageURL);
Image image = icon.getImage();
g.drawImage(image, x, y, null);
}
public static void drawText(Graphics2D g, String text, int centerx, int centery){
if(text == null)
throw new IllegalArgumentException("Text is null in drawText function!");
FontMetrics metrics = g.getFontMetrics();
int w = metrics.stringWidth(text);
int h = metrics.getDescent();
g.drawString(text, centerx - w/2, centery + h);
}
}
线段端点
线段拐点
抗锯齿
双缓存
用户看不到画布被清空的一瞬间,也就不会有闪烁的效果了。
概率模拟问题
气泡随机移动(关键字circle)
- 随机生成圆心坐标
- 如何检测之间的碰撞
随机模拟问题(关键字:Money)
房间内有100人,每人有100块钱,每分钟随机的一个人给另一个人1块钱,在一段时间后,这100个人的财富状况是怎样的?
蒙特卡多算法
蒙特卡洛(摩纳哥赌城)方法是一种统计学的方法;是一种模拟。
蒙特卡洛模拟是二战期间,为解决原子弹研制工作中,裂变物质的中子随机扩散问题,美国数学家冯诺伊曼和乌拉姆等提出的一种统计方法,代号:蒙特卡洛。
通过大量随机样本,去了解一个系统,进而得到所要计算的值。
- 拉斯维加斯算法
- 蒙特卡洛求PI值(关键字:PI)
用蒙特卡洛投点法计算Pi的值;
在一个边长为a的正方形内一均匀概率随机投点,该点落在此正方形的内切圆中的概率即为内切圆与正方形的面积比值,即:Pi * (a / 2)^2 : a^2 = Pi / 4。
- 1.随着投点的次数增加,圆周率Pi计算的准确率在增加;
- 2.但当次数达到一定规模时,准确率精度增加在减缓,其原因是生成的随机数是伪随机的,这也是蒙特卡洛算法达不到祖冲之求圆周率精度的内在原因;
- 3.同时在进行两次的1亿次投点中也可以发现,对于相同的投点数由于实验本身的随机性每次的实验结果是不同的
三门问题(关键字:ThreeGatesExperiment)
三门问题:一个节目中,参赛者会看见三扇关闭的门,其中一扇的后面有一辆汽车。当参赛者选定一扇门,但未开启它的时候,节目主持人会开启剩下两扇门的一扇没有汽车的门。之后,主持人问参赛者要不要换另外一扇门?问题是:换另外一扇门会否增加参赛者赢得汽车的概率?
出自美国的电视游戏节目Let’s Make a Deal。问题的名字来自该节目的主持人蒙提·霍尔(Monty Hall)。
结论:换门的话,中奖率为2/3,不换门的话,中奖率为1/3
public class ThreeGatesExperiment {
private int N;
public ThreeGatesExperiment(int N){
if(N <= 0)
throw new IllegalArgumentException("N must be larger than 0!");
this.N = N;
}
public void run(boolean changeDoor){
int wins = 0;
for(int i = 0 ; i < N ; i ++)
if(play(changeDoor))
wins ++;
System.out.println(changeDoor ? "Change" : "Not Change");
System.out.println("winning rate: " + (double)wins/N);
}
private boolean play(boolean changeDoor){
// Door 0, 1, 2
int prizeDoor = (int)(Math.random() * 3);
int playerChoice = (int)(Math.random() * 3);
if( playerChoice == prizeDoor)
// 不换门中奖
return changeDoor ? false : true;
else
// 换门中奖
return changeDoor ? true : false;
}
public static void main(String[] args) {
int N = 10000000;
ThreeGatesExperiment exp = new ThreeGatesExperiment(N);
exp.run(true);
System.out.println();
exp.run(false);
}
}
原理:
P(0号门中奖)+P(1号门中奖)+P(2号门中奖)=1
P(0号门中奖)=1/3
P(1号门中奖)+P(2号门中奖)=2/3
P(1号门中奖)=0=>P(2号门中奖)=2/3
你一定能中奖吗?(关键字WinningPrize)
在游戏里,有一种宝箱,打开这个宝箱获得传奇武器的概率是20%,现在你打开5个这样的宝箱,获得传奇武器的概率是多少?
排序可视化
选择排序 (关键字selectionsort)
选择排序是交换最少的排序,当交换需要的复杂度极高时,比如排序集装箱
插入排序(关键字insert)
归并排序 (merge)