在时间复杂度为nlogn下读取文件求逆序对

问题:
对于一个包含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();
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值