PageRank的Java代碼實現及圖形操作(帶詳細註釋)!

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);
	}

}


發佈了24 篇原創文章 · 獲贊 19 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章