nerviges Logik Problem
-
Hi,
ich hab ein Logik Problem (denke ich), da ich in diesem Forum immer die schlauesten Antworten bekommen hab, wollte ich Euch mal dazu befragen. Das Problem:
Ein Segment bestet aus einer Anfangsadresse (0 bis naja, is egal) und einer Endadresse (1 bis unendlich, unendlich heisst fuer end == 0) auf einem "Zahlenstrahl" (darf man das so nennen ?!).
In einem Programm sollen verschiedene Segmente nun eingegeben werden koennen, also jeweils "Start" und "Ende". Diese werden dann in einer ArrayList gespeichert werden, bzw einer davon abgeleiteten Klasse SegmentList.
Bedingungen nun sind, ueberlagern sich zwei Segmente A und B, so verschmelzen sie, dh aus A und B bleibt ein drittes C, welches in die Liste eingetragen wird. Dieses hat nun den niedrigeren "Start" und das hoehere "Ende" jeweils der beiden A und B. Das ganze sollte geordnet in die Liste eingetragen werden, dh die niedrieger liegenden Segmente ganz unten. Wie gesagt, eine 0 fuer "Ende" heisst bis unendlich (naja, soviel wie int halt hergibt, ich weiss gar nich wie gross das eigentlich ist, da gabs glaub ich mal so ne Methode... egal 0 ist unendlich).
Zum loeschen der Segmente sollten im Programm einfach die CheckBoxen abgewaehlt werden. Daher beim ausprobieren bitte das erste Segment 0 bis 0/ende abwahlen - logisch, alles andre laege ja dazwischen.Ich sitz da nun schon seit gestern an dem Algorithmus rum und glaube, dass ich mich erinnern kann da mal eine Vorgehensweise fuer sowas gelernt zu haben, wie man sowas am besten entwickelt - ich habe aber hier leider keine Unterlagen da, also hab ichs durchgeholzt und so siehts eben aus.
Der Algorithmus fuer das einfuegen der Segmente ist in der Methode "setNewSegment(Segment)" in der Klasse "SegmentList". Das ist mein Problem. Ich poste aber hier gleich mal noch ein kleines Fensterchen dazu, damit man das vielleicht daheim laufen lassen kann und es einfacher hat mir zu helfen. Das Programm laeuft soweit - ich hoffe es ist fehlerfrei. Ich bin zwar fuer jegliche Kritik auch am Fenstergebastel offen, sage aber gleich dazu, dass es aus einem anderen Projekt von mir stammt und nur mal eben schnell hingetrasht ist. Das Problem ist wie gesagt die Klasse SegmentList.
Fragen:
1. Wie entwickelt man so einen Algorithmus am besten (hier ich suche evtl Schlagworte, nach denen ich vielleicht auch googeln kann oder Links im Netz direkt)?
2. Ist mein geholze eigentlich fehlerfrei, kann mir jemand helfen das zu verbessern, bzw mir Tipps geben (uebersichtlichkeit etc, ach ja, die vielen System.out.println hab ich zum debuggen reingehaun)?
3. Wie sieht sowas eleganter in Java aus, kann man das eleganter loesen?
4. Wenn man wirklich die ganzen if/else Dinger brauchen wuerde, wie liesse sich so etwas dann eleganter implementieren, fuer C etwa?Ich wuerde mich wirklich freuen, wenn mir jemand versuchen wuerde zu helfen, da ich einiges versucht hab, ich diese Loesung aber total umstaendlich finde - Danke im Vorraus!!!!!
Code - erst mal diese wiederspenstige SegmentList:
package testalgo; import java.util.ArrayList; public class SegmentList extends ArrayList{ // ctor /** * public SegmentList(int i) * * ctor with i elements */ public SegmentList(int i){ super(i); } /** * public void setNewSegment(Segment newSegment) * * make sure that e.g. the unckecked JCheckBox entries * are ereased before! */ public void setNewSegment(Segment newSegment){ int idxStart=0; int cnt=0; System.out.println("#############################################################################################"); System.out.println("setNewSegment::istart: " + newSegment.getIStart() + "; iend: " + newSegment.getIEnd()); /** * check values * * check if it makes sense to enter the algo * return */ // values too big, too small too whatever... if((newSegment.getIEnd()!= 0) && ((newSegment.getIStart() > newSegment.getIEnd()) || (newSegment.getIStart() < 0) || (newSegment.getIEnd() < 0))){ System.out.println("SegmentList::setNewColSegment()::Start > End -> cancel, end");// return; } // SegmentList is empty, simply add it on... // return if(this.size() == 0){ add(newSegment); System.out.println("this.size() == 0; list was empty -> add without checking, end");// return; } /** * entering the algo - check and obtain istart */ // run to the position for(cnt=0; (this.size() > cnt) && (newSegment.getIStart() > ((Segment) this.get(cnt)).getIStart()); cnt++) ; System.out.println("check start, cnt: " + cnt);// // ran thru? - add new segment // return if(cnt == this.size() && (((Segment) this.get(cnt-1)).getIEnd() != 0) && (((Segment) this.get(cnt-1)).getIEnd() < newSegment.getIStart())){ this.add(newSegment); System.out.println("cnt == this.size(); ran thru, add at last, end");// return; // if cnt == 0, newSegment.getIStart() was 0 }else if(cnt == 0){ // must be separate, cnt-1 could fail otherwise idxStart = cnt; System.out.println("cnt == 0; istart was 0 or before the first element -> set idxStart to 0 now");// if((newSegment.getIEnd() < ((Segment) this.get(cnt)).getIStart()) && (newSegment.getIEnd() != 0)){ System.out.println("newSegment was completely before any other element"); this.add(cnt, newSegment); return; } }else if((newSegment.getIStart() <= ((Segment) this.get(cnt-1)).getIEnd()) || (((Segment) this.get(cnt-1)).getIEnd() == 0)){ newSegment.setIStart(((Segment) this.get(cnt-1)).getIStart()); idxStart = cnt-1; System.out.println("istart <= this(cnt-1).iend; istart is overlapping the last element -> set idxStart to cnt-1: " + (cnt-1));// }else{ idxStart = cnt; System.out.println("else; not overlapping, istart is in a gap before the element cnt: " + cnt);// } System.out.println("idxStart: " + idxStart);// // idxStart is now determinded, this will be the // first index to remove old segments and to insert // the segment, istart is also known now /** * check end */ // if iend == 0, add and done if(newSegment.getIEnd() == 0){ System.out.println("iend() == 0, add it and done; end"); this.removeRange(idxStart, this.size()); this.add(newSegment); return; } for(cnt=idxStart; (cnt < this.size()) && (newSegment.getIEnd() > ((Segment) this.get(cnt)).getIEnd()) && (((Segment) this.get(cnt)).getIEnd() != 0);cnt++) ; System.out.println("check end, cnt: " + cnt);// /** * ran thru? * * cnt== this.size() has to be checked, risk of cnt == 0, cnt-1 doesn't exist!!! * * this.getIend == 0 thus cnt-1 is the last element!!! * -> in all cases the new segment will need to get 0 at iend * -> return * */ if(cnt == this.size()){ if(((Segment) this.get(cnt-1)).getIEnd() == 0){ System.out.println("this(cnt-1).iend == 0; it is definitely the last element; end"); newSegment.setIEnd(0); this.remove(cnt-1); this.add(newSegment); return; } //keep iend is bigger than this'es iend, but it is not 0 !!! cnt--; System.out.println("cnt = this.size(); ran thru, end is after the last one -> cnt-- so now: " + cnt + " iend is set to 0, iend: " + newSegment.getIEnd());// }else if(newSegment.getIEnd() >= ((Segment) this.get(cnt)).getIStart()){ // needs to be "else if" newSegment.setIEnd(((Segment) this.get(cnt)).getIEnd()); System.out.println("iend >= this(cnt).istart; iend is overlapping, merge -> new iend is now: " + newSegment.getIEnd());// } /** * removing & inserting newSegment * * decides if it is necessary to delete a range or just a single entry */ System.out.println("removeRange; this.size() before: " + this.size() + "; idxStart: " + idxStart + " thru cnt: " + cnt);// if(!this.isEmpty() && (idxStart == cnt)){ System.out.println("remove one element; list was NOT empty (double check)");// this.remove(cnt); }else{ this.removeRange(idxStart, cnt); System.out.println("removeRange; this.size() is now: " + this.size() + "; idxStart: " + idxStart + " thru cnt: " + cnt);// } // insert new segment - ArrayList.add() does the job of insert() this.add( idxStart, newSegment); System.out.println("added at idx; this.size() should now be one more: " + this.size());// System.out.println("over and out"); } // returns the segments as a string able to be presented public String getSegmentAsString(int cnt, String szSegment, String szThru, String szEnd){ if(((Segment) this.get(cnt)).getIEnd() == 0){ return (cnt + szSegment + ((Segment) this.get(cnt)).getIStart() + szThru + szEnd); }else{ return (cnt + szSegment + ((Segment) this.get(cnt)).getIStart() + szThru + ((Segment) this.get(cnt)).getIEnd()); } } }
Nun das Fenster zum austesten:
package testalgo; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.*; import javax.swing.text.*; import javax.swing.InputMap; import javax.swing.JFrame; import javax.swing.JButton; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; public class JFrameSegment extends JFrame { private JTextField tfStart; private JTextField tfEnd; private JButton butNew, butOk; private JCheckBox[] jcbSegments; private SegmentList slSegments; private JPanel jpSegments; private JScrollPane scrollPane; // ctor JFrameSegment(){ slSegments = new SegmentList(1); slSegments.add(new Segment(0,0)); drawJFrameSegment(); } /** * public DialogSegment drawDialogSegment() * * draws the dialog */ public JFrameSegment drawJFrameSegment(){ (this.getContentPane()).setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS)); // label and start textfield JPanel jpFirstLine = new JPanel(); jpFirstLine.setLayout(new FlowLayout()); JLabel labelStart = new JLabel("start:"); jpFirstLine.add(labelStart); JPanel jpStart = new JPanel(new FlowLayout()); tfStart = new JTextField(9); tfStart.setDocument(new IntegerDocument(9)); jpStart.add(tfStart); jpFirstLine.add(jpStart); (this.getContentPane()).add(jpFirstLine); // label and end textfield JPanel jpSecLine = new JPanel(); jpSecLine.setLayout(new FlowLayout()); JLabel labelEnd = new JLabel("End: "); jpSecLine.add(labelEnd); JPanel jpEnd = new JPanel(new FlowLayout()); tfEnd = new JTextField(9); tfEnd.setDocument(new IntegerDocument(9)); jpEnd.add(tfEnd); jpSecLine.add(jpEnd); (this.getContentPane()).add(jpSecLine); JPanel jpNew = new JPanel(new FlowLayout()); butNew = new JButton("New"); InputMap mapNew = butNew.getInputMap(); mapNew.put( KeyStroke.getKeyStroke("ENTER"), "pressed" ); mapNew.put( KeyStroke.getKeyStroke("released ENTER"), "released" ); jpNew.add(butNew); (this.getContentPane()).add(jpNew); // set default values setDefaultEntries(); // Segments jpSegments = new JPanel(); jpSegments = drawSegments(); scrollPane = new JScrollPane(jpSegments); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); (this.getContentPane()).add(scrollPane); // New - AcionListener butNew.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ if((ae.getSource()).equals(butNew)){ removeUnchecked(); if( ((tfStart.getText()).length() > 0) && ((tfEnd.getText()).length() > 0)){ slSegments.setNewSegment(new Segment(Integer.parseInt((String) tfStart.getText()), Integer.parseInt((String) tfEnd.getText()))); } jpSegments = drawSegments(); scrollPane.setViewportView(jpSegments); setDefaultEntries(); jpSegments.repaint(); } } }); // general window opions: this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("quite simple frame"); this.setLocation(400, 200); this.setResizable(false); this.setSize(400,400);//// this.setVisible(true); return this; } /** * private JPanel drawSegments() * * draws Segment panel */ private JPanel drawSegments(){ // show the segments JPanel panel = new JPanel(); JPanel jpNewSegments = new JPanel(); jpNewSegments.setLayout(new BoxLayout(jpNewSegments, BoxLayout.Y_AXIS)); jcbSegments = new JCheckBox[slSegments.size()]; for(int cnt=0; cnt<slSegments.size(); cnt++){ jcbSegments[cnt] = new JCheckBox(); jcbSegments[cnt].setText(slSegments.getSegmentAsString(cnt, ". Segment ", " thru ", " end")); jcbSegments[cnt].setSelected(true); jpNewSegments.add(jcbSegments[cnt]); } panel.add(jpNewSegments); return panel; } /** * private void removeUnchecked() * * removes unchecked segments */ private void removeUnchecked(){ for(int cnt=0; cnt<slSegments.size(); cnt++){ if(jcbSegments[cnt].isSelected() == false){ slSegments.remove(cnt); } } } /** * private void closeDialog() * * closes window */ private void closeDialog(){ this.setVisible(false); this.dispose(); } /** * private void setDefaultEntries() * */ private void setDefaultEntries(){ (this.tfStart).setText("0"); // fixme - entry in Options (this.tfStart).selectAll(); (this.tfEnd).setText("0"); } //////////////////////////////////////////////////////////////////////////// public static void main(String[] args){ JFrameSegment jfs = new JFrameSegment(); } class IntegerDocument extends PlainDocument{ private int maxCharacter = -1; // ctor /** * inits the max amount of characters */ public IntegerDocument( int len){ maxCharacter = len; } // set option /** * allows only integers in the textfield */ public void insertString(int offset, String str, AttributeSet attributeSet) throws BadLocationException{ try{ if((str != null) && (maxCharacter > 0) && ((this.getLength() + str.length()) > maxCharacter)){ java.awt.Toolkit.getDefaultToolkit().beep(); return; } ////// Integer.parseInt(str); } catch(Exception exception){ Toolkit.getDefaultToolkit().beep(); return; } super.insertString( offset, str, attributeSet); } } }
...und die nur wenig aufregende Klasse Segment selbst, damit sollte es laufen:
package testalgo; public class Segment { private int iStart; private int iEnd; // ctor public Segment(int start, int end){ setIStart(start); setIEnd(end); // 0 means up to eof } /** * @return Returns the iEnd. */ public int getIEnd() { return iEnd; } /** * @param end The iEnd to set. */ public void setIEnd(int end) { if((iStart>end) && (end != 0)){ iEnd = 0; }else{ iEnd = end; } } /** * @return Returns the iStart. */ public int getIStart() { return iStart; } /** * @param start The iStart to set. */ public void setIStart(int start) { iStart = start; } }