Τρίτη 5 Ιανουαρίου 2016

Συνδεδεμένη Λίστα - και Malloc σε Μ2000.

Άλλο ένα πρόγραμμα στα Αγγλικά. Έχουμε δυο κλάσεις. Μια μας παρέχει το χώρο για να βάλουμε μια δομή συνδεδεμένης λίστας. Και η δεύτερη είναι αυτή που φτιάχνει το κάθε στοιχείο που θα συνδέσουμε. Η Μ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



Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.