Άλλο ένα πρόγραμμα στα Αγγλικά. Έχουμε δυο κλάσεις. Μια μας παρέχει το χώρο για να βάλουμε μια δομή συνδεδεμένης λίστας. Και η δεύτερη είναι αυτή που φτιάχνει το κάθε στοιχείο που θα συνδέσουμε. Η Μ2000 δεν παρέχει στο χρήστη μνήμη και δείκτες για χρήση. Αυτό που παρέχει είναι πίνακες (που δυναμικά αν θέλουμε αυξομειώνονται) και αντικείμενα ως στοιχεία πινάκων. Τα δε αντικείμενα μπορούν να έχουν και πίνακες άρα και άλλα αντικείμενα. Δεν θέλουμε να φτιάξουμε "φωλιασμένα" αντικείμενα. Θέλουμε να βρίσκονται στην μνήμη και να έχουν ένα δείκτη που θα δείχνει το επόμενο μέχρι εκείνο όπου ο δείκτης θα έχει το -1.
Η κλάση MEM φτιάχνει ένα αντικείμενο Μ και το οποίο μας δίνει την δυνατότητα να βάζουμε ότι αντικείμενα θέλουμε και όχι ειδικά αντικείμενα συνδεδεμένης λίστας. Μας παρέχει ένα Malloc, όπου τοποθετούμε ένα φρέσκο αντικείμενο και μας επιστρέφει τον δείκτη που δείχνει σε πιο στοιχείο του πίνακα μπήκε. Επιπλέον μας παρέχει μια MFree που με αυτήν και τον δείκτη που πήραμε πριν μπορούμε να σβήσουμε το αντικείμενο και να επαναφέρουμε την μνήμη αυτή ως διαθέσιμη. Μάλιστα το αντικείμενο M βάζει τα ήδη χρησιμοποιούμενα στοιχεία σε μια συνδεδεμένη λίστα.
Για την κύρια συνδεδεμένη λίστα έχουμε δυο ρουτίνες. (χρησιμοποίησα ρουτίνες για να μην περνάω με αναφορά το αντικείμενο Μ. Θα μπορούσα να το κάνω γενικό ή να το περνάω με &M σε κάθε συνάρτηση αλλά με τις ρουτίνες αποφεύγω όλη αυτή την διαδικασία.
Οι δυο ρουτίνες κάνουν τη προσθήκη και τη διαγραφή στοιχείου. Και επειδή αλλάζουν την ρίζα (σχετικό είναι αυτό, θα μπορούσαμε να το λέμε κορυφή), αυτή μπαίνει με αναφορά. Ο τρόπος αυτός είναι καθαρά για να φαίνεται πιο μαζεμένο το πρόγραμμα. Η τρίτη ρουτίνα απλά μας εμφανίζει όλα τα στοιχεία (μόνο το item, έναν αριθμό δηλαδή). Στο mList υπάρχει και το name$. Αυτό μπήκε μετά. Μπορούμε να το σβήσουμε καθώς και όλες τις εντολές που έχουν το name$. Μπήκε καθαρά για να φανεί πόσο απλό είναι να προσθέσουμε κάτι σε αντικείμενο χωρίς να πειράξουμε όλη την άλλη λογική.
Ο πίνακας στην Μ δεν είναι δυναμικός, επειδή δεν τον χρησιμοποιούμε έτσι. Αν θέλουμε γράφουμε περισσότερες εντολές και γίνεται να μπορούμε να τον αυξήσουμε. Για να τον ελαττώσουμε μάλλον δεν είναι εύκολο αν υπάρχουν συνδεδεμένα στοιχεία. Είναι το ίδιο με το defragmentation των αρχείων στο δίσκο.
Αυτό που δεν φαίνεται εκ πρώτης όψης είναι ότι η συνδεδεμένη λίστα θα μπορούσε να είχε και από ένα αντικείμενο, ένα ΜΕΜ() και εντέλει σε μια "μνήμη" έστω 100 στοιχείων να έχω συνδεδεμένες λίστες καθεμία με "μνήμη" διαφορετικού μεγέθους.
Στις συναρτήσεις της κλάσης ΜΕΜ() έχουμε και δυο, την Property() και την Property$() για να διαβάσουμε ιδιότητες από τα αποθηκευμένα στοιχεία έμμεσα. Περνάμε την ιδιότητα σαν αλφαριθμητικό.
(διόρθωσα την ΜΕΜ() για να επιστρέφει το NoUsed όταν υπάρχει προηγούμενο διαγραμμένο)
Gosub Myclass ' define Mem() class function
\\ this is mList with a name$, an item Number and a pnext For pointer
Class mList {
name$="ok"
item
pnext=-1
}
' If we have functions in mList Then we can make them common
' In Mem class
' M=Mem(100, mList())
M=Mem(100)
oneRoot=M.Null()
For i=9 To 0
Gosub PushOne(&oneRoot, i**2)
Next i
Gosub Disp(OneRoot)
Print M.IsNull(30), M.IsNull(2), M.count
Gosub DelOne(&oneRoot, 9) '' If we give , 0 Then root is moving to 8
Print M.count, oneRoot, M.topfree
Print M.Property(oneRoot,"item", 1000) ' change item, return old value
Print M.Property(oneRoot,"item") \\ 1000
Print M.Property$(oneRoot,"name$","Good")
Print M.Property$(oneRoot,"name$") \\ Good
\\ add one more
Gosub PushOne(&oneRoot, 1234)
Print M.count, oneRoot, M.topfree
\\ add one more
Gosub PushOne(&oneRoot, 5678)
Print M.count, oneRoot, M.topfree
End
Sub PushOne(&Root, item)
Local kk
kk=m.Malloc(mlist())
For m.d(kk) {
.item=item
.pnext=Root
Root=kk
}
End Sub
Sub DelOne(&root, item)
Local walk=root, walk1=root
While walk >-1 {
For m.d(walk) {
If .item=item Then {
If root=walk Then {
root=.pnext
} Else {
m.d(walk1).pnext=.pnext
}
walk1=walk
walk=-2
} Else walk1=walk :walk=.pnext
}
If walk=-2 Then m.Mfree walk1
}
End Sub
Sub Disp(walk)
While walk >-1 {
For m.d(walk) {
Print .item
walk=.pnext
}
}
End Sub
MyClass:
Class Mem {
Dim d()
noUsed=-1
topfree=0
Items, Count
Group Null { Null }
Function Null {
=-1
}
Function IsNull {
=Valid(.d(Number).Null)
}
Module Mem {
Read .Items
If Match("G") Then Read N
N=.Null \\ this is a Union If N is a Group
Dim .d(.Items)=N
}
Function Malloc {
If .noUsed=-1 Then {
If .topfree<.Items Then {
Read .d(.topfree)
=.topfree
.topfree++
.count++
} Else Error "Memory Full"
} Else {
temp=.d(.noUsed).Null
Read .d(.noUsed)
=.noUsed
.noUsed<=temp
.count++
}
}
Module Mfree {
Read mf
If .IsNull(mf) Then Error "Invalid Pointer"
old=.noUsed
.noUsed<=mf
.d(mf)=.Null
.d(mf).Null<=old
.count--
}
Function Property {
Read A, A$
A$=".d(A)."+A$ ' M2000 has string pointers
If .IsNull(A) Then Error "Invalid Pointer"
=Eval(A$)
If Match("N") Then A$.=Number
}
Function Property$ {
Read A, A$
A$=".d(A)."+A$
If .IsNull(A) Then Error "Invalid Pointer"
=Eval$(A$.) ' look . after A$
\\ A$. is not A$ is a pointer To
If Match("S") Then A$. = letter$
}
}
Return
Η κλάση MEM φτιάχνει ένα αντικείμενο Μ και το οποίο μας δίνει την δυνατότητα να βάζουμε ότι αντικείμενα θέλουμε και όχι ειδικά αντικείμενα συνδεδεμένης λίστας. Μας παρέχει ένα Malloc, όπου τοποθετούμε ένα φρέσκο αντικείμενο και μας επιστρέφει τον δείκτη που δείχνει σε πιο στοιχείο του πίνακα μπήκε. Επιπλέον μας παρέχει μια MFree που με αυτήν και τον δείκτη που πήραμε πριν μπορούμε να σβήσουμε το αντικείμενο και να επαναφέρουμε την μνήμη αυτή ως διαθέσιμη. Μάλιστα το αντικείμενο M βάζει τα ήδη χρησιμοποιούμενα στοιχεία σε μια συνδεδεμένη λίστα.
Για την κύρια συνδεδεμένη λίστα έχουμε δυο ρουτίνες. (χρησιμοποίησα ρουτίνες για να μην περνάω με αναφορά το αντικείμενο Μ. Θα μπορούσα να το κάνω γενικό ή να το περνάω με &M σε κάθε συνάρτηση αλλά με τις ρουτίνες αποφεύγω όλη αυτή την διαδικασία.
Οι δυο ρουτίνες κάνουν τη προσθήκη και τη διαγραφή στοιχείου. Και επειδή αλλάζουν την ρίζα (σχετικό είναι αυτό, θα μπορούσαμε να το λέμε κορυφή), αυτή μπαίνει με αναφορά. Ο τρόπος αυτός είναι καθαρά για να φαίνεται πιο μαζεμένο το πρόγραμμα. Η τρίτη ρουτίνα απλά μας εμφανίζει όλα τα στοιχεία (μόνο το item, έναν αριθμό δηλαδή). Στο mList υπάρχει και το name$. Αυτό μπήκε μετά. Μπορούμε να το σβήσουμε καθώς και όλες τις εντολές που έχουν το name$. Μπήκε καθαρά για να φανεί πόσο απλό είναι να προσθέσουμε κάτι σε αντικείμενο χωρίς να πειράξουμε όλη την άλλη λογική.
Ο πίνακας στην Μ δεν είναι δυναμικός, επειδή δεν τον χρησιμοποιούμε έτσι. Αν θέλουμε γράφουμε περισσότερες εντολές και γίνεται να μπορούμε να τον αυξήσουμε. Για να τον ελαττώσουμε μάλλον δεν είναι εύκολο αν υπάρχουν συνδεδεμένα στοιχεία. Είναι το ίδιο με το defragmentation των αρχείων στο δίσκο.
Αυτό που δεν φαίνεται εκ πρώτης όψης είναι ότι η συνδεδεμένη λίστα θα μπορούσε να είχε και από ένα αντικείμενο, ένα ΜΕΜ() και εντέλει σε μια "μνήμη" έστω 100 στοιχείων να έχω συνδεδεμένες λίστες καθεμία με "μνήμη" διαφορετικού μεγέθους.
Στις συναρτήσεις της κλάσης ΜΕΜ() έχουμε και δυο, την Property() και την Property$() για να διαβάσουμε ιδιότητες από τα αποθηκευμένα στοιχεία έμμεσα. Περνάμε την ιδιότητα σαν αλφαριθμητικό.
(διόρθωσα την ΜΕΜ() για να επιστρέφει το NoUsed όταν υπάρχει προηγούμενο διαγραμμένο)
Gosub Myclass ' define Mem() class function
\\ this is mList with a name$, an item Number and a pnext For pointer
Class mList {
name$="ok"
item
pnext=-1
}
' If we have functions in mList Then we can make them common
' In Mem class
' M=Mem(100, mList())
M=Mem(100)
oneRoot=M.Null()
For i=9 To 0
Gosub PushOne(&oneRoot, i**2)
Next i
Gosub Disp(OneRoot)
Print M.IsNull(30), M.IsNull(2), M.count
Gosub DelOne(&oneRoot, 9) '' If we give , 0 Then root is moving to 8
Print M.count, oneRoot, M.topfree
Print M.Property(oneRoot,"item", 1000) ' change item, return old value
Print M.Property(oneRoot,"item") \\ 1000
Print M.Property$(oneRoot,"name$","Good")
Print M.Property$(oneRoot,"name$") \\ Good
\\ add one more
Gosub PushOne(&oneRoot, 1234)
Print M.count, oneRoot, M.topfree
\\ add one more
Gosub PushOne(&oneRoot, 5678)
Print M.count, oneRoot, M.topfree
End
Sub PushOne(&Root, item)
Local kk
kk=m.Malloc(mlist())
For m.d(kk) {
.item=item
.pnext=Root
Root=kk
}
End Sub
Sub DelOne(&root, item)
Local walk=root, walk1=root
While walk >-1 {
For m.d(walk) {
If .item=item Then {
If root=walk Then {
root=.pnext
} Else {
m.d(walk1).pnext=.pnext
}
walk1=walk
walk=-2
} Else walk1=walk :walk=.pnext
}
If walk=-2 Then m.Mfree walk1
}
End Sub
Sub Disp(walk)
While walk >-1 {
For m.d(walk) {
Print .item
walk=.pnext
}
}
End Sub
MyClass:
Class Mem {
Dim d()
noUsed=-1
topfree=0
Items, Count
Group Null { Null }
Function Null {
=-1
}
Function IsNull {
=Valid(.d(Number).Null)
}
Module Mem {
Read .Items
If Match("G") Then Read N
N=.Null \\ this is a Union If N is a Group
Dim .d(.Items)=N
}
Function Malloc {
If .noUsed=-1 Then {
If .topfree<.Items Then {
Read .d(.topfree)
=.topfree
.topfree++
.count++
} Else Error "Memory Full"
} Else {
temp=.d(.noUsed).Null
Read .d(.noUsed)
=.noUsed
.noUsed<=temp
.count++
}
}
Module Mfree {
Read mf
If .IsNull(mf) Then Error "Invalid Pointer"
old=.noUsed
.noUsed<=mf
.d(mf)=.Null
.d(mf).Null<=old
.count--
}
Function Property {
Read A, A$
A$=".d(A)."+A$ ' M2000 has string pointers
If .IsNull(A) Then Error "Invalid Pointer"
=Eval(A$)
If Match("N") Then A$.=Number
}
Function Property$ {
Read A, A$
A$=".d(A)."+A$
If .IsNull(A) Then Error "Invalid Pointer"
=Eval$(A$.) ' look . after A$
\\ A$. is not A$ is a pointer To
If Match("S") Then A$. = letter$
}
}
Return
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.