问题:
对于一个包含N个非负整数的数组A[1…n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。
例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。
给定一个数组,求该数组中包含多少个逆序对。
要求时间复杂度为nlog(n)
package ho1;
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 java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileSystemView;
/**
* 实现:
* 1.通过按钮选择文件
* 2.读取文件中内容,转化为整数数组
* 3.在时间复杂度为nlog(n)要求下通过分治算法求出逆序对
* 2019年10月24日
*/
public class NIXu extends JFrame implements ActionListener {
JButton open = null;
//读取的文件
File txt;
//转换后的数组
String[] myArray ;
/*
* 選擇文件的函數
*/
public NIXu() {
// 按钮组件
open = new JButton("请选择要读取的文件");
this.add(open);
this.setBounds(800, 400, 400, 150);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
open.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = new JFileChooser();
FileSystemView fsv = FileSystemView.getFileSystemView();
jfc.setCurrentDirectory(fsv.getHomeDirectory());
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
if (jfc.showOpenDialog(NIXu.this) == JFileChooser.APPROVE_OPTION) {
File file = jfc.getSelectedFile();
if (file.isDirectory()) {
System.out.println("文件夹:" + file.getAbsolutePath());
} else if (file.isFile()) {
txt = new File( file.getAbsolutePath());
ReadFile(txt);
//System.out.println("文件:" + file.getAbsolutePath());
// 关闭窗口
this.dispose();
}
}
}
/*
* 讀取txt的函數
* 返回的是字符串数组,在下一个函数中我把它转为了整数数组
*/
public static void ReadFile(File file){
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
List<Integer> list = new ArrayList<Integer>();
while ((line = br.readLine()) != null) {
// 这里我暂且定为:每行的第一个字符是数字,而且是一位数,在实际中需要在做处理
//line = line.substring(0, 3);
//System.out.println(line);
list.add(Integer.parseInt(line));
}
// intarray为读取到的数组,放入merge中
if (!list.isEmpty()) {
int[] intArray = new int[list.size()];
for (int i = 0; i < intArray.length; i++) {
intArray[i] = list.get(i);
}
System.out.println("读取到的数组为"+list);
System.out.println("逆序对的数量是"+merge_sort(intArray,0,intArray.length-1));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 倒置数的检测函数
* 因为题目要求:复杂度最坏 Θ(nlgn)
* 可以考虑归并排序
*/
public static int merge_sort(int[] arr,int begin,int end){
int sum=0;
int left=0;
int right=0;
int q=0;
if(begin<end)
{
int mid=(begin+end)/2;//拆分待排序元素
left=merge_sort(arr,begin,mid);//获取左侧子序列的逆序数
right=merge_sort(arr,mid+1,end);//获取右侧子序列的逆序数
sum=merge(arr,begin,mid,end);//左、右子序列合并在一起时,子序列的逆序已经数好,这里要数剩余的那些逆序对的数量。
}
return sum+left+right;
}
/**
*
* @return
*/
private static int merge(int A[],int begin, int mid, int end) {
int count = 0;
int[] w = new int[end-begin+1];
int i = begin;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= end) {
if (A[i] <= A[j]) {
w[k ++] = A[i ++];
}
else {
count += mid - i + 1;
w[k ++] = A[j ++];
}
}
while (j <= end)
w [k ++] = A[j ++];
while (i <= mid)
w[k ++] = A[i ++];
for (k = 0; k < end - begin + 1;k ++)
A[begin + k] = w[k];
return count;
}
public static void main(String[] args) {
new NIXu();
}
}