编程实现 4 条重写规则,有友好的接口。输入任意字后,可生成(1)半法式和(2)法式,并且注明每一步应用了哪一个重写规则。给出源程序和可以执行的程序。
/**
* @author 康雨城
* @time 2017/10/17
* csdn : http://blog.csdn.net/kangyucheng
* * 运行说明:在任何IDE中创建java Project,然后将创建class命名为Main,将本段代码复制进去即可运行。
*/
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 输入字w
ArrayList<Word> inputList=new ArrayList<Word>();//存储输入字
ArrayList<Word> subNormalList=new ArrayList<Word>();//存储半法式
ArrayList<Word> normalList=new ArrayList<>();//存储法式
//输入任意字
inputList=getInputList();
System.out.println("输入数据为:");printList(inputList);
System.out.println("其中每组数字第一个数字代表下标,第二个数字1代表正字母,-1代表负字母");
//按照NF1的要求进行排序,得到半法式
subNormalList=sort(inputList);
System.out.println("半法式为:");printList(subNormalList);
//删除违规二元组得到法式
normalList=subNormalToNormal(subNormalList);
System.out.println("法式为:");printList(normalList);
}
private static ArrayList<Word> getInputList() {
// 分为随机输入和手动输入两种
ArrayList<Word> list=new ArrayList<Word>();
Scanner input =new Scanner(System.in);
System.out.println("需要手动输入请按y或Y并按回车键,按任意键后并按回车键系统将为您自动输入一组测试数据");
char c=input.next().charAt(0);
if(c=='Y'||c=='y'){
System.out.println("请按以下格式输入数据: a b 回车。(中间有空格)a为非负数,b为1或-1,当输入0 0时,系统结束输入");
System.out.println("例如: \n3 1回车\n6 -1回车\n9 -1回车 \n8 -1回车 \n1 -1回车 \n0 0回车\n");
System.out.println("或者按照以下格式输入:3 1 6 -1 9 -1 8 -1 1 -1 2 1 0 0");
System.out.println("其中每两个数字一组,每组数字第一个数字代表下标,第二个数字1代表正字母,-1代表负字母");
while(true){
int inKey=input.nextInt();
int inLetter=input.nextInt();
if(inKey==0&&inLetter==0)break;
list.add(new Word(inKey,inLetter));
}
}
else{
//以下数字可计算题目中的(2)
// list.add(new Word(5,-1));
// list.add(new Word(3,1));
// list.add(new Word(7,1));
// list.add(new Word(9,-1));
// list.add(new Word(4,-1));
//以下数字可计算题目中的(3)
// list.add(new Word(3,-1));
// list.add(new Word(2,1));
// list.add(new Word(7,1));
// list.add(new Word(9,-1));
// list.add(new Word(4,-1));
// list.add(new Word(1,-1));
//以下数字可计算题目中的(4)
// list.add(new Word(0,1));
// list.add(new Word(5,-1));
// list.add(new Word(3,1));
// list.add(new Word(7,1));
// list.add(new Word(11,1));
// list.add(new Word(9,-1));
// list.add(new Word(4,-1));
// list.add(new Word(0,-1));
// list.add(new Word(0,-1));
// list.add(new Word(0,-1));
// list.add(new Word(0,-1));
//以下式子可以实现消除最大违规二元组
list.add(new Word(7,1));
list.add(new Word(9,1));
list.add(new Word(4,-1));
list.add(new Word(1,-1));
list.add(new Word(10,-1));
list.add(new Word(11,1));
list.add(new Word(13,1));
list.add(new Word(7,-1));
list.add(new Word(1,-1));
list.add(new Word(15,-1));
//以下狮子可以是反证(4)的例子
// list.add(new Word(0,1));
// list.add(new Word(3,-1));
// list.add(new Word(0,1));
// list.add(new Word(2,1));
// list.add(new Word(5,1));
// list.add(new Word(4,-1));
// list.add(new Word(3,-1));
}
input.close();
return list;
}
private static ArrayList<Word> sort(ArrayList<Word> list) {
// 冒泡排序的方法写成半法式
int length=list.size();
for(int i=0;i<length;i++){
for(int j=0;j<length-i-1;j++){
Word word1=list.get(j);
Word word2=list.get(j+1);
int key1=word1.getKey();
int key2=word2.getKey();
if(word1.getLetter()==Word.POSITIVE
&&word2.getLetter()==Word.NEGETIVE){
//正字母在左,负字母在右,不交换位置
}
else if(word1.getLetter()==Word.NEGETIVE
&&word2.getLetter()==Word.POSITIVE){
//负字母在左,正字母在右,只有左侧下标小于右侧下标的情况需要交换位置
if(word1.getKey()<word2.getKey()){
//负字母在左,且负字母下标较小 满足i<k条件 应用R3
list.get(j).setKey(key2+1);
list.get(j).setLetter(Word.POSITIVE);
list.get(j+1).setKey(key1);
list.get(j+1).setLetter(Word.NEGETIVE);
System.out.print("应用一次R3,得到:");printList(list);
}
else{
//负字母在左,且负字母下标较大 应用 R2
list.get(j).setKey(key2);
list.get(j).setLetter(Word.POSITIVE);
list.get(j+1).setKey(key1+1);
list.get(j+1).setLetter(Word.NEGETIVE);
System.out.print("应用一次R2,得到:");printList(list);
}
}
else if(word1.getLetter()==Word.POSITIVE
&&word2.getLetter()==Word.POSITIVE){
//两个字母都是正字母的情况,只有左侧下标大于右侧下标的情况需要交换位置
if(word1.getKey()>word2.getKey()){
list.get(j).setKey(key2);
list.get(j+1).setKey(key1+1);
System.out.print("应用一次R1,得到:");printList(list);
}
}
else{
//两个字母都是负字母的情况,只有左侧下标小于右侧下标的情况需要交换位置
if(word1.getKey()<word2.getKey()){
list.get(j).setKey(key2+1);
list.get(j+1).setKey(key1);
System.out.print("应用一次R4,得到:");printList(list);
}
}
}
}
return list;
}
private static ArrayList<Word> subNormalToNormal(ArrayList<Word> list) {
//通过删除违规二元组,将半法式转化为法式
int maxKeyIndex=getMaxKeyIndex(list);
int left=maxKeyIndex,right=maxKeyIndex+1;
while(left>=0&&right<list.size()){
int pkey=list.get(left).getKey();
int rkey=list.get(right).getKey();
if(pkey<rkey){
right++;
}
else if(pkey>rkey){
left--;
}
else{
int nextPkey=list.get(left+1).getKey();
int nextRkey=list.get(right-1).getKey();
if((nextPkey!=pkey+1)&&(nextRkey!=rkey+1)){
//已找到最大违规二元组,开始消除
System.out.println("找到最大违规二元组:("+pkey+",1) 和 ("+rkey+",-1)");
int cr1=0,cr4=0;
if(left+1!=right){
//违规二元组中间有字母,与中间字母进行交换
for(int l=left+1;l<=maxKeyIndex;l++){
list.get(l).keyMul();
//System.out.print("应用一次R1,得到:");printList(list);
cr1++;
}
for(int r=right-1;r>maxKeyIndex;r--){
list.get(r).keyMul();
//System.out.print("应用一次R4,得到:");printList(list);
cr4++;
}
}
//删除字母,并修改左右指针。
list.remove(list.get(left));
left--;right--;
list.remove(list.get(right));
System.out.print("应用"+cr1+"次R1,应用"+cr4+"次R4,应用一次R5,删除了最大违规二元组,得到:");printList(list);
}
}
}
return list;
}
private static int getMaxKeyIndex(ArrayList<Word> list) {
//获取正字母中下标最大的元素,因为已经是排列完成的半法式,
//所以,只需要找到两个正字母和负字母的交界即可
int i=0;
for(int j=0;j<list.size();j++){
if(list.get(j).getLetter()==1&&
list.get(j+1).getLetter()==-1){
i=j;
break;
}
}
return i;
}
private static void printList(ArrayList<Word> list) {
//打印数组
for(int i=0;i<list.size();i++){
System.out.print(list.get(i).getKey()+" "+list.get(i).getLetter() +" ");
}
System.out.println();
}
}
class Word{
public static int POSITIVE=1;//正字母
public static int NEGETIVE=-1;//负字母
private int key;//下标
private int letter;//正负字母标识
public Word(int key, int letter) {
this.key = key;
this.letter = letter;
}
public Word() {
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public int getLetter() {
return letter;
}
public void setLetter(int letter) {
this.letter = letter;
}
public void keyMul() {
this.key--;
}
}