PageRank的Java代码实现及图形操作(带详细注释)!
从Git上找到的一段代码,修改了一些东西,加了一些自己遇到的问题的注释以及增加了阻尼系数变量。
废话不说直接上代码:
package cn.wx.PageRank; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; /** * 求取PageRank值的代码 用户可以通过文件选择器选择读入指定的文件进行计算,文件的第一行为初始PR值, * * 余下的行为矩阵,其中矩阵行元素间用“,”隔开,行与行之间无需分隔符。 * * 也可以通过选择随机来输入矩阵的维数、初始PR值以及矩阵的复杂度(矩阵中有多少个1)生成矩阵进行计算。 */ public class newPageRank { static JTextField jtf;// 显示文件路径的框 static JTextArea jta;// 显示计算结果的框 static JFrame jf;// 显示的窗体 static JFrame jf1;// 显示输入矩阵的窗体 static float[] data;// 存数输入数据的数组 static int time = 20;// 指定的运行次数 static float alpha = 0.85f; // 阻尼系数d或称为alpha public static void main(String[] args) { newPageRank mine = new newPageRank(); mine.showUI(); } /** * 展示计算结果的界面 */ public void showUI() { // 初始化界面以及按钮、输入框等 jf = new JFrame(); jf.setTitle("PR值计算~~"); jf.setSize(500, 500); jf.setDefaultCloseOperation(3); jf.setResizable(false); jf.setLayout(null); jf.setLocationRelativeTo(null); JButton btn = new JButton("打开"); btn.setActionCommand("Open"); btn.setBounds(20, 20, 80, 30); JButton btn1 = new JButton("随机"); btn1.setActionCommand("Input"); btn1.setBounds(110, 20, 80, 30); jtf = new JTextField(); jtf.setBounds(200, 20, 260, 30); jtf.setEditable(true); jtf.setActionCommand("Over"); jta = new JTextArea(); jta.setEditable(false); jta.setLineWrap(true); jta.setAutoscrolls(true); JScrollPane jsp = new JScrollPane(jta);// 创建滚动条 jsp.setBounds(20, 70, 460, 380); // 添加监听器 ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Open")) { // 弹出选择框 jta.setText("");// 每次重新选择之前清空输入框 JFileChooser fc = new JFileChooser(); int value = fc.showOpenDialog(null); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); if (value == JFileChooser.CANCEL_OPTION) { return; } File file = fc.getSelectedFile(); jtf.setText(file.getAbsolutePath()); readFile(file); } if (e.getActionCommand().equals("Input")) { init();// 初始化窗体,获取值 } if (e.getActionCommand().equals("Over")) { jta.setText(""); // 输入路径结束,执行以下操作 File file = new File(jtf.getText()); readFile(file); } } }; jf.add(btn); jf.add(btn1); jf.add(jtf); jf.add(jsp); btn.addActionListener(al); btn1.addActionListener(al); jtf.addActionListener(al); jf.setVisible(true); } /** * 读取相应路径文件的方法 定义文件中第一行是节点对应的初始化PR值, * 接下来是N*N的矩阵 同行数据之间均通过","分隔,不同行无需分隔符 * * @param file * :文件 */ public static void readFile(File file) { try { // 创建读文件的流 FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String PR = br.readLine(); String[] sPR = PR.split(",");// 将第一行PR值存入对应数组 // 将读取的PR值从String转为float float[] initPR = new float[sPR.length]; for (int i = 0; i < sPR.length; i++) { initPR[i] = Float.parseFloat(sPR[i]); } jta.append("各页面的初始PR值………………………………………………………………" + "\n"); for (int i = 0; i < initPR.length; i++) { jta.append(initPR[i] + "\t");// 打印出PR值 } jta.append("\n"); // 读取并创建N*N矩阵,在这里使用float,精度为小数点后7位 float[][] array = new float[initPR.length][initPR.length]; int count = 0;// 用计数器控制行的变化 // 当行数小于指定数N时进行读取 while (count < initPR.length) { String value = br.readLine();// 读取一行的值 String[] rowV = value.split(","); // 对第count行第i列赋值 for (int i = 0; i < initPR.length; i++) { array[count][i] = Float.parseFloat(rowV[i]); } count++; } jta.append("原始矩阵为………………………………………………………" + "\n"); print(array);// 打印出矩阵 // 读取完成后,调用计算的函数对矩阵进行计算 long start = System.currentTimeMillis(); calculate(initPR, array); long end = System.currentTimeMillis(); jta.append("total time is:" + (end - start)); br.close(); // 关闭流 } catch (FileNotFoundException e) { javax.swing.JOptionPane.showMessageDialog(jf, "文件未找到,请重试!"); } catch (IOException e) { javax.swing.JOptionPane.showMessageDialog(jf, "文件读取有误,请重试!"); } } /** * 打印矩阵的方法 * * @param s */ static void print(float[][] f) { for (int i = 0; i < f.length; i++) { for (int j = 0; j < f.length; j++) { jta.append(f[i][j] + "\t"); } jta.append("\n"); } } /** * 计算矩阵特征值以及特征向量的方法 * * @param initPR * :存储初始的PR值的float数组 * @param array * :存储初始矩阵的float二维数组 */ static void calculate(float[] initPR, float[][] array) { array = changeRC(array);// 转置矩阵 jta.append("转置后的矩阵…………………………………………………………"); jta.append("\n"); print(array); array = randomization(array);// 概率化矩阵 jta.append("\n"); jta.append("概率化后的矩阵………………………………………………………………"); jta.append("\n"); print(array); for (int i = 1; i <= time; i++) { initPR = formular(initPR, array); jta.append("\n"); jta.append("经过" + i + "次计算,PR值为………………………………………………"); jta.append("\n"); for (int j = 0; j < initPR.length; j++) { jta.append("PR[" + j + "]的值为:" + initPR[j]); jta.append("\n"); } } jta.repaint(); } /** * 转置矩阵的方法 * * @param array * :需要转置的矩阵 * @return:将转置后的矩阵返回 */ static float[][] changeRC(float[][] array) { float temp = 0;// 临时变量,用于交换 for (int i = 0; i < array.length; i++) { for (int j = 0; j < array.length; j++) { // 对矩阵的每一行、列遍历,如果下标i<j就倒换 if (i < j) { temp = array[i][j]; array[i][j] = array[j][i]; array[j][i] = temp; } } } return array; } /** * 概率化矩阵的方法 * * @param array * :需要概率化的矩阵 * @return:返回已经概率化的矩阵 */ static float[][] randomization(float[][] array) { int count = 0;// 控制列变化的计数器 int size = 0;// 计量列中连接为1的元素数量的计数器 while (count < array.length) { size = 0;// 每次计数之前要清零 for (int i = 0; i < array.length; i++) { if (array[i][count] == 1) { size++;// 先统计出数量为多少 } } jta.append("the size of " + count + " is:" + size + " "); for (int i = 0; i < array.length; i++) { if (array[i][count] == 1) { array[i][count] = (float) 1 / size; } } count++; } return array; } /** * 通过公式计算PR值 * * @param initPR * :初始PR值 * @param array * :经处理的矩阵 * @return:返回计算后的PR值 */ static float[] formular(float[] initPR, float[][] array) { for (int i = 0; i < initPR.length; i++) { initPR[i] = 0;// 重算一个PR之前,将其清零 int count = 0;// 计量每一行0元素个数 for (int j = 0; j < initPR.length; j++) { if (i != j && array[i][j] != 0) { initPR[i] = (float) (initPR[i] + ((initPR[j] * array[i][j]) * alpha + (1.0f-alpha))); } else count++; } if (count == initPR.length) { initPR[i] = (float) 0.15; } } return initPR; } static void input(float[] data) { float size = data[0]; float complex = data[1]; float[] initPR = new float[data.length - 2]; for (int i = 0; i < initPR.length; i++) { initPR[i] = data[i + 2]; } float[][] array = new float[(int) size][(int) size];// 创建输入大小的矩阵 // 初始化矩阵元素为0 for (int i = 0; i < array.length; i++) { for (int j = 0; j < array.length; j++) { array[i][j] = 0; } } int num = (int) (complex / 100 * array.length * array.length);// 需要被赋为1的元素个数 // 为矩阵按照复杂程度赋值 while (num > 0) { int row = (int) (Math.random() * (array.length)); int column = (int) (Math.random() * (array.length));// 随机生成行列数 if (row != column && array[row][column] != 1) { array[row][column] = 1; num--; } } // 打印随机生成的PR和矩阵 jta.append("各页面的初始PR值………………………………………………………………" + "\n"); for (int i = 0; i < initPR.length; i++) { jta.append(initPR[i] + "\t");// 打印出PR值 } jta.append("\n"); jta.append("生成的矩阵…………………………………………………………………………" + "\n"); print(array); // 将计算好的初始PR数组和矩阵传入计算 long start = System.currentTimeMillis(); calculate(initPR, array); long end = System.currentTimeMillis(); jta.append("total time is:" + (end - start)); } /** * 初始化一个输入值的窗体 */ static void init() { jf1 = new JFrame("生成随机矩阵"); jf1.setSize(300, 160); jf1.setResizable(false); jf1.setDefaultCloseOperation(2); jf1.setLocationRelativeTo(null); jf1.setLayout(new FlowLayout()); JLabel lb = new JLabel("矩阵维度:"); final JTextField jtf = new JTextField(15); JLabel lb1 = new JLabel("初始PR值:"); final JTextField jtf1 = new JTextField(15); JLabel lb2 = new JLabel(" 复杂度: "); final JTextField jtf2 = new JTextField(15); jtf2.setActionCommand("sure"); JLabel lb3 = new JLabel("% "); JButton btn = new JButton("确认"); btn.setActionCommand("sure"); JButton btn1 = new JButton("取消"); btn1.setActionCommand("cancle"); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("sure")) { // 点击确认后,存储输入值 float size = Integer.parseInt(jtf.getText());// 取值 String[] s = jtf1.getText().split(","); float complex = Integer.parseInt(jtf2.getText()); // 初始化数组,将输入框中的值存入数组 data = new float[s.length + 2]; // 先存入矩阵维度,再放入复杂度,最后存入各个初始值 data[0] = size; data[1] = complex; for (int i = 0; i < s.length; i++) { data[2 + i] = Float.parseFloat(s[i]); } jf1.dispose(); input(data); } if (e.getActionCommand().equals("cancle")) { jf1.dispose(); } } }; jf1.add(lb); jf1.add(jtf); jf1.add(lb1); jf1.add(jtf1); jf1.add(lb2); jf1.add(jtf2); jf1.add(lb3); jf1.add(btn); jf1.add(btn1); jtf2.addActionListener(al); btn.addActionListener(al); btn1.addActionListener(al); jf1.setVisible(true); } }