| |||||||
Du magst keine Werbung? Wir auch nicht!
Einfach registrieren und die Werbung ist weg. Diese Nachricht sehen nur nicht registrierte Nutzer.
![]() |
| | LinkBack | Themen-Optionen | Ansicht |
| | #1 (permalink) |
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
| "LinkedList" einfach verkettete Liste, Probleme bei Umsetzung
Ich wollte eine Verkettete Liste als Klasse zu erstellen. Dabei fehlt mir aber des öfteren einfach der Überblick was man doch lieber in eine Extraklasse packen sollte und was nicht. Momentan sieht das bis jetzt so aus: Interface "IList" Code: interface IList
{
function isEmpty(): Boolean
// function insert( o: Object ): Boolean
function insert( index: Number , o: Object ): Boolean
function remove( o: Object ): Boolean
function clear(): Void
function contains( o: Object ): Boolean
} Code: class Linkable
{
public var o: Object;
public var next: Linkable;
public function Linkable( o: Object )
{
this.o = o;
next = null;
}
} Code: class LinkedList
implements IList
{
private var fstE: Object; // first Element
private var lstE: Object; // last Elemnt
private var l: Number; // how many elements "contains" the list
public function LinkedList( link: Object )
{
if( arguments.length )
{
lstE = fstE = new Linkable( link );
l = 1;
}
else
{
fstE = lstE = new Object();
l = 0;
}
}
public function clear(): Void
{
var tmp1: Object = fstE;
var tmp2: Object = tmp1.next;
while( tmp1 != null )
{
deleteLink( tmp1 );
tmp1 = tmp2;
tmp2 = tmp2.next;
}
l = 0;
}
private function deleteLink( link: Object ): Void
{
link.next = link.o = null;
delete link;
}
public function get first(): Object
{
return isEmpty() ? null : fstE.o;
}
public function get last(): Object
{
return isEmpty() ? null : lstE.o;
}
public function isEmpty(): Boolean
{
return ! l;
}
public function get length(): Number
{
return l;
}
public function contains( o: Object ): Boolean
{
var tmp: Object = fstE;
while( tmp.o != lstE.o )
{
if( tmp.o == o ) return true;
tmp = tmp.next;
}
return false;
}
public function push( o: Object ): Void
{
if( ! contains( o ) )
{
lstE.next = new Linkable( o );
lstE = lstE.next;
l++;
}
}
public function insert( index: Number , o: Object ): Boolean
{
if( ! isEmpty() )
{
if( index < length && index >= 0 )
{
if( ! contains( o ) )
{
var i = 0;
var tmp: Object = fstE;
while( i++ < index ) tmp = tmp.next;
if( i != index )
{
tmp.o = o;
l++;
return true;
}
}
}
}
return false;
}
public function remove( o: Object ): Boolean
{
if( ! isEmpty() )
{
var tmp: Object = fstE;
while( (tmp.next.o != o) && (tmp.next.next != null) ) tmp = tmp.next;
if( tmp.next.o != o ) return false;
deleteLink( tmp.next );
lstE = tmp;
l--;
return true;
}
return false;
}
public function pop(): Boolean
{
if( ! isEmpty() )
{
var tmp: Object = fstE;
while( tmp.next.next != null ) tmp = tmp.next;
deleteLink( tmp.next );
lstE = tmp;
l--;
return true;
}
return false;
}
} "LinkedList": - meine Membervariablen der Klasse "LinkedList" habe ich als "Object" definiert und nicht als "Linkable", da ich diese nur als Pointer nutzen und nur die Referenz auf das erste und das letzte Element in diesen speichern will. Dabei hab ich immer die Funktionsweise von C-Pointern vor Augen, kann man das ungefähr vergleichen oder ist das bei Flash komplett anders? - Wenn ich die Funktion "clear" aufrufe, will ich ja alle Elemente der Liste löschen, also die angelegten Referenzen. Nun ist mir aber folgendes aufgefallen: PHP-Code: Eigentlich dürfte das Objekt nicht gelöscht werden da doch eine Referenz auf dieses in der Klasse "LinkedList" besteht. Und bei beiden gibt delete jeweils true zurück (?), sollte das eigentlich nicht erst passieren wenn keine Referenz mehr auf diese Objekt existiert? Und wie könnte man am besten prüfen ob meine Klasse auch wirklich die Objekte wieder freigibt so das der GC diese Objekte "zerstören" kann. "IList": - In diesem Interface würde ich gerne die Funktion "insert" so wie sie auskommentiert ist implementieren, da ja nicht jede Liste unbedingt ein einfügen innerhalb der Liste benötigt (z.B.: Stack, Queue, ...). Wie könnte man dies noch "Ausmerzen"? Oder ist es da besser noch ein Interface für die genannten Ausnahmen zu erstellen? Und nun auch eine Frage die vielleicht schon eher in diesen Bereich passt... - Könnte man die Klassen so lassen, oder würde sich da noch eine Unterteilung, ein besserer Aufbau, etc. anbieten? - Wie sieht es mit einer Sortierung so einer "einfach" verketteten Liste aus? Das dürfte doch sehr problematisch werden, da ja nur der Nachfolger bekannt ist. Da müsste man schon merfach mit dem BubbleSort durchgehen, oder gibt es da was was sich für so etwas anbietet? So, hoffentlich antwortet da noch einer bei der Masse an Input... Geändert von rendner[i] (18-02-2006 um 19:11 Uhr) |
| | |
| | #2 (permalink) |
| \x3a\x6f\x29 Registriert seit: Apr 2004 Ort: paris
Beiträge: 806
|
Nur zum schauen: http://je2050.de/stuff.php?p=/source/de/je2050/util/ Bin grade nur über die Überschrift gestolpert, aber schreibe gerne später etwas mehr dazu! |
| | |
| | #3 (permalink) |
| \x3a\x6f\x29 Registriert seit: Apr 2004 Ort: paris
Beiträge: 806
|
1.) Sortierung Ein Link zur sortierten Liste von mir: SortedList Der Trick ist: Beim Einfügen eines Elements in die Liste checkst du, ob es kleiner als der Start-Knoten ist, usw. Das geht man ganz einfach Rekursiv durch. Eine extra sortier-Funktion ist auch nicht so schwer. Das habe ich in Pascal auch schon mal machen müssen glaube ich. Vielleicht finde ich die noch und könnte dir das am Mittwoch schicken. 2.) Clear Problem Ich verstehe leider noch nicht ganz, wo der Unterschied zwischen deinen Beiden Versionen ist. 3.) IList und insert() Ehrlichgesagt würde ich ein anderes Design wählen. Bei dir ist jedes List-Element die ganze Liste(?). Also einfacher ist es, wenn du ein Start-Knoten explizit hast, der von einem (List-)Element erbt und die Liste/Queue/Stack Funktionen bietet. 4.) Aufbau Wie erwähnt. Ich würde eine Liste wie folgt aufbauen: - Listen Element (Beinhaltet dynamischen Datentyp und Pointer) - Datentyp (Funktionen wie toString, zum Vergleich etc.) - Builder (Erbt vom standart Element und handhabt die Bewegungen inerhalb deiner Struktur, wie Liste/Stack/Queue) Möchtest du z.B. eine einfache Liste haben, hast du deine simple List. Willst du eine sortierte Liste haben, musst du nur die insert-Funktion der List überschreiben und schon hast du eine sortierte Liste usw. |
| | |
| | #4 (permalink) | |||
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
|
Habe mir deine Sachen mal angeguckt, find ich schön Struckturiert (da ich immer zum "alles-in-einer-Klasse" programmieren neige). Was mir besonders gefallen hat war die Sache mit dem Datentypen ("IData"). Zitat:
Die Funktion push und der Konstruktor tragen jeweils das übergebene Objekt in der art "pointer = new Linkable( object );" in die Liste. Danach "lösche" ich das Objekt, in Version1 ist meine Referenz gelöscht, das Objekt ist weg, aber warum? Und in Version2 habe ich Zugriff auf das Objekt, so wie es nach meiner Auffassung auch sein sollte. Zitat:
Das kommt daher das ich nur an Pointer gedacht habe .Zitat:
Gut das werd ich mal Sacken lassen und bei gegebener Freizeit mal umsetzen. Geändert von rendner[i] (18-02-2006 um 19:13 Uhr) | |||
| | |
| | #5 (permalink) |
| \x3a\x6f\x29 Registriert seit: Apr 2004 Ort: paris
Beiträge: 806
|
Also anfangen würde ich mit einer einfachen Liste. Was bei jeder Liste von dir gleich sein wird ist das Listen-Element. Grob ist ein Listenelement aufgebaut aus: - Pointer auf nächstes Element - Daten Das kann man ja simpel in einer Klasse festhalten (genannt Element). Schon kannst du deine einfache Liste bauen, die aus den einfachen Elementen besteht. Bei dir besitzt zur Zeit jedes Element alle Funktionen. Ich würde jetzt anders vorgehen. Dazu schreibst du eine neue Klasse "List" z.B. List erweitert Element, also "List extends Element" (ich will nicht kindisch wirken, aber so kann man leichter folgen glaube ich und weiß sofort was gemeint ist). Deine List Klasse verfügt jetzt über die eigenschaften eines Elements. Was fehlt sind die Funktionen. Also z.B. eine Funktion zum einfügen. Dazu schreibst du in die List die Funktion insert(), wie du es auch kennst. Schon hättest du eine Liste, bei der nur die Basis-Klasse über insert(), delete() usw. bescheid weiß. Das spart auch Resourcen, bei größeren Datenmengen z.B. Als nächstes möchtest du vielleicht eine automatisch sortierte Liste schreiben. Die delete() oder exists() Funktionen kannst du noch von der anderen Liste übernehmen. Nur die insert() Funktion müsstest du jetzt überschreiben. Also eine neue Klasse SortedList oder so anlegen, welche List erweitert. In dieser musst du nur die insert() Funktion überschreiben und du hast deine Sortierte Liste. So kannst du immer weiter machen, mit Stack, Queue usw. Stack würde ich z.B. von Element erben lassen und dann nur push() und pop() als Funktionen definieren. Mehr weiß der Stack-Typ ja eigentlich nicht. Fals es dich interessiert, kannst du dir auch mal die Bäume anschauen. |
| | |
| | #6 (permalink) |
| muh Registriert seit: Apr 2002 Ort: Freiburg
Beiträge: 4.350
|
Also ich weiß nicht, was eine LinkedList ist, und wofür man sie braucht, aber deine Umsetzung scheint mir etwas wackelig. Beispielsweise die push-Methode ist mir ungeheuer, solltest du beabsichtigen, beim ersten push-Aufruf sowohl in lstE als auch in fstE zu schreiben (es sind ja die gleichen Objekte), dann würde ich versuchen, das expliziter zu tun. Warum sind eigentlich fstE und lstE keine Elemente? Und warum heißen sie nicht einfach fistElement und lastElement? Wofür braucht man denn sowas? Erinnert mich irgendwie an die XML-Klasse.
__________________ »Carpe diem«, sagte der Graf. (Terry Pratchett: Ruhig Blut!) |
| | |
| | #7 (permalink) | ||||
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
| Zitat:
Zitat:
Wenn man ein Objekt einem anderen Objekt zuweist, speichert man ja nur eine Referenz auf dieses. Darum habe ich mir gedacht diese gleich als Objekt zu lassen, da fstE und lstE nicht die Methoden, Variablen der Klasse "Linkable" (Element) brauchen. Zitat:
Zitat:
Aber der Vorteil gegenüber einem Array ist (zumindest in C), das du nicht wieder das Array neu anlegen musst wenn du ein Element in ein volles Array zusätzlich einfügen willst. Da du ja nur die Verweise auf den Nachfolger verändern musst. Geändert von rendner[i] (20-02-2006 um 01:15 Uhr) | ||||
| | |
| | #8 (permalink) | ||
| muh Registriert seit: Apr 2002 Ort: Freiburg
Beiträge: 4.350
| Zitat:
Zitat:
Sollte pop nicht das Element (eine Referenz darauf) zurück geben?
__________________ »Carpe diem«, sagte der Graf. (Terry Pratchett: Ruhig Blut!) | ||
| | |
| | #9 (permalink) | ||
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
| Zitat:
Ich habe ja in fstE eine Referenz von dem Objekt gespeichert und somit kann ich ja auch dessen Methoden benutzen, dafür muss ich diese doch nicht auch selber besitzen. Zitat:
Somit kann man dann auch "normal" pop'en. | ||
| | |
| | #10 (permalink) |
| muh Registriert seit: Apr 2002 Ort: Freiburg
Beiträge: 4.350
|
Dass du weißt, dass du in fstE ein Objekt mit den Eigenschaften next und o speicherst, hilft dem Compiler herzlich wenig. Wenn du jetzt auf fstE.mext zugreifst wirst du keine Warnung bekommen …
__________________ »Carpe diem«, sagte der Graf. (Terry Pratchett: Ruhig Blut!) |
| | |
| | #11 (permalink) |
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
|
Ja ich verstehe schon was du meinst, aber auf next und o des Objektes greift nur die Liste selber zu. Und wenn die Liste das erste oder letzte gespeicherte Objekt zurückgegeben soll, dann wird vorher geprüft ob die Liste leer ist. Aber ich werds dann doch so machen das die Pointer fstE und lastE ebenfalls vom Element erben. |
| | |
| | #12 (permalink) |
| voidboy Registriert seit: Sep 2004 Ort: München
Beiträge: 5.588
|
So hab die Liste überarbeitet, hoffe das kommt schon eher einer verketteten Liste nahe. Sehr grosse Probleme hatte ich beim "umdenken" wenn Elemente eingefügt oder gelöscht werden sollen, hatte gedacht man kann da einfach die Zeiger tauschen und gut is, aber das hat so nicht geklappt. Dürfte so doch jetzt eigentlich gehen, oder? Klasse ListElement: (Das Interface IData, ist das von [je]. Link -->IData) Code: class ListElement
{
private var data: IData;
private var next: ListElement;
public function ListElement( data: IData )
{
this.data = data;
next = null;
}
public function getNext(): ListElement
{
return next;
}
public function setNext( e: ListElement ): Void
{
next = e;
}
public function getData(): IData
{
return data;
}
public function setData( data: IData ): Void
{
this.data = data;
}
public function clone(): ListElement
{
var e: ListElement = new ListElement( data );
e.setNext( next );
return e;
}
public function copy( e: ListElement ): Void
{
setData( e.getData() );
setNext( e.getNext() );
}
public function clear()
{
setData( null );
setNext( null );
}
} Code: class LinkedList extends ListElement
{
private var l: Number; // length of the LinkedList
public function LinkedList()
{
super( null );
l = 0;
}
public function insert( d: IData ): Void
{
var e: ListElement = new ListElement( d );
e.setNext( clone() );
copy( e );
l++;
}
public function remove(): Void
{
if( l )
{
copy( getNext() );
l--;
}
}
public function insertAt( index: Number , d: IData ): Boolean
{
if( index == 0 )
{
insert( d );
return true;
}
if( l < index ) return false;
var i: Number = 1;
var e: ListElement = new ListElement( d );
var p: ListElement = searchElement( index - 1 );
e.setNext( p.getNext().clone() );
p.getNext().copy( e );
l++;
return true;
}
public function removeAt( index: Number ): Boolean
{
if( index == 0 && l )
{
remove();
return true;
}
if( l <= index ) return false;
var p: ListElement = searchElement( index - 1 );
if( p.getNext().getNext() == null )
{
p.setNext( null );
}
else
{
var e: ListElement = new ListElement();
e.copy( p.getNext() );
p.getNext().copy( e.getNext().clone() );
e.clear();
}
l--;
return true;
}
public function get head(): IData
{
return getData();
}
public function getAt( index: Number ): IData
{
if( index == 0 ) return head;
return searchElement( index ).getData();
}
private function searchElement( index: Number ): ListElement
{
var p: ListElement = new ListElement( null );
var i: Number = 0;
p.copy( this );
while( i++ < index )
{
p.copy( p.getNext() );
}
return p;
}
public function isEmpty(): Boolean
{
return l == 0 ? true : false;
}
public function get length(): Number
{
return l;
}
public function clear(): Void
{
while( getNext() != null )
{
setNext( getNext().getNext() );
}
super.clear();
l = 0;
}
} |
| | |
![]() |
| Lesezeichen |
| Themen-Optionen | |
| Ansicht | |
| |