Da tale forum ne bo tako sameval
Saj veste kako je s kazalci v C ali C++: kazalcu prirediš lokacijo spremenljivke in potem z njim počneš kar hočeš. Preko njega lahko dostopaš do vrednosti spremenljivke ali pa mu prirediš lokacijo druge spremenljivke. Ali obstaja kaj takega v VB.NET?
Konkreten primer:
Recimo, da imam razred Node, ki mi predstavlja vozlišče v trojiškem drevesu (vsako vozlišče ima vrednost tipa String in največ 3 sinove):
Class Node
Public left As Node 'polja bi seveda morala biti property-i... pa pustimo to
Public middle As Node
Public right As Node
Public value As String
End Class
Seveda lahko kličem proceduro in podam node po referenci:
Sub KrNeki (ByRef myNode As Node)
Pri tem klicu se bo myNode res obnašal kot kazalec.
Kaj pa drug primer: recimo, da bi rada znotraj procedure preverila, kateri od sinov vozlišča vsebuje niz nekNiz in tistega od sinov zamenjala z drugim vozliščem:
Dim theNode as Node 'sin, ki vsebuje vrednost nekNiz
If myNode.left.value = nekNiz Then
theNode = myNode.left
ElseIf myNode.middle.value = nekNiz Then
theNode = myNode.middle
ElseIf myNode.right.value = nekNiz Then
theNode = myNode.right
End If
theNode = GenerateRandomNode("new node value")
Skratka, če je veljalo myNode.middle.value = nekNiz, potem bi rada, da se to vozlišče zamenja z novim in velja myNode.middle.value = "new node value". Vendar se to ni zgodilo. Vozlišče theNode sicer ima novo vrednost, vendar ta ne vpliva na vozlišče myNode.middle, ki je ostalo takšno kot prej.
Če bi imela na voljo kazalce, bi v kazalec shranila referenco na myNode.middle in ne bi bilo nobenih problemov.
A sem kaj spregledala? Vem, da obstaja razred Pointer, ampak VB.NET ne dovoli uporabe njegovih metod.
AndrejT - sreda, 22. marec 2006
Ja, LinkedList ti omogoča delo z množico nekih elementov recimo v tvojem primeru števil), ki so med seboj povezane (lahko v drevo) in se po njih lahko sprehajaš preko referenčnih povezav. Po drugem tvojem postu pa vidim, da te to ne zanima
newdrim - sreda, 22. marec 2006
AndrejT: ne razumem, kako bi si pomagala z LinkedList... a zato, da bi v njem hranila sinove vozlišča ali kako?
newdrim - sreda, 22. marec 2006
ExAmigan, moje vprašanje se v resnici ne nanaša na vsebino problema (operacije nad drevesom), ampak na kazalce kot take. Problem z drevesom je dodan le kot ilustracija (očitno ne preveč dobra). Kot sem napisala v zadnjem postu, sem zadevo rešila točno tako kot si sam svetoval: klicala sem metodo, ki je sprejela parameter po referenci, namesto po vrednosti. Hec je v tem, da se mi zdijo kazalci bolj naravni za take operacije. Glede na to, da sem zbudila toliko zanimanja (hvala, fantje - makes me feel special ), vam bom pa še razkrila kako dejansko izgleda koda. Imam drevo, ki ima naslednjo (zelo neuporabno) lastnost: v vozliščih so naravna števila. Če je ostanek pri deljenju s 3 enak 0, spada število v levo poddrevo, če je enak 1 spada v srednje poddrevo in če je enak 2 spada v desno poddrevo. Če neposredno pod trenutnim vozliščem ni prostora (ker ima vozlišče že sina v danem poddrevesu), se spustim nivo nižje in spet delim s 3 (zato imam v spodnji kodi spremenljivki guide in remainder). Skratka, spodnja koda je rešitev problema in IMHO deluje b.p. Vprašanje je le, ali v VB.NET obstajajo kazalci (ker bi raje delala z njimi ko bom imela naslednjič podobno situacijo). Pa še to: seveda se da zadevo veliko bolj elegantno in brez kakršne koli potrebe po kazalcih rešiti rekurzivno. Tudi to sem že naredila . Zanimajo me samo kazalci (sem izbirčna, kaj?). Public Sub InsertIterative(ByRef rootNode As TreeNode, ByVal value As Integer) Dim wasInserted As Boolean = False Dim guide As Integer = value Dim node As TreeNode = rootNode 'če je rootNode = Nothing, ustvarimo novo vozlišče wasInserted = CreateNewNode(rootNode, value) 'sicer poiščemo ustrezno mesto za novo vozlišče While Not wasInserted Dim remainder As Integer = guide Mod 3 guide = guide \ 3 If guide = 0 Then guide = value Select Case remainder Case 0 wasInserted = CreateNewNode(node.Left, value) node = node.Left Case 1 wasInserted = CreateNewNode(node.Middle, value) node = node.Middle Case 2 wasInserted = CreateNewNode(node.Right, value) node = node.Right End Select End While End Sub 'če je node = Nothing, popravimo referenco tako, da kaže na novo ustvarjeno vozlišče in'vrnemo true; sicer vrnemo false in ne naredimo ničesarPrivate Function CreateNewNode(ByRef node As TreeNode, ByVal value As Integer) As Boolean If node Is Nothing Then node = New TreeNode(value) Return True End If Return FalseEnd Function
AndrejT - sreda, 22. marec 2006
Mogoče ni direktno povezano s tvojim vprašanjem, ampak tvoj problem bi bil znal biti rešljiv tudi z uporabo LinkedList(Of string), z nekaj "dodatne opreme". Če ne drugega, je vsaj za pogledat kot princip referenc in povezanih vozlišč...
ExAmigan - sreda, 22. marec 2006
Nisem povsem prepričan, da razumem, kaj želiš izvesti v metodi PrerazporediSinove(Node), a če želiš da se sprememba parametra kot zamenjava objekta, na katerega ta kaže (torej kot zamenjava vrednosti kazalca), odrazi navzven, potem se moraš pač poslužiti prenosa po referenci. V primeru prenosa po vrednosti se bodo nasprotno odrazile le spremembe v objektu, ne pa tudi parametra samega. VB.NET je v tem pogledu skladen z delovanjem Jave in C#, konceptualno pa se mi to tudi ne zdi toliko drugačno od kazalcev v C/C++, čeprav priznam, da sem v tem jeziku že malo zarjavel. Ob ponovnem branju svojega odgovora upam, da sem dovolj jasen, sicer pa je najbolje, da podaš celoten primer, kaj želiš doseči.
newdrim - torek, 21. marec 2006
Ah, saj sem vedela, da bi si morala izmisliti boljši primer. Pa reciva, da tega ne moreš narediti, ker so operacije, ki jih nameravaš izvesti nekako odvisne od lastnosti theNode. Recimo, da theNode = GenerateRandomNode("new node value") zamenjam z theNode = PrerazporediSinove(theNode) Če se pa se želim iterativno (torej brez rekurzije) sprehajati po takem drevesu glede na vrednosti v vozliščih in vmes vstavljati nova vozlišča, lahko postane kar zabavno V mojem primeru sem tiste stvari, ki sem jih hotela narediti z vozliščem, dala kar v svojo proceduro, ki sem ji podala vozlišče po referenci. Procedura je zato lahko spremenila karkoli, vključno z zamenjavo vozlišča, ampak bi si želela narediti zadevo s kazalci, če je to mogoče. IntPtr sicer predstavlja referenco na košček memorije, samo ne vem, kako bi mu priredila naslov kakšnega objekta.
MihaM - torek, 21. marec 2006
Živjo Andreja, V tvojem primeru je theNode samo reference na enega od otrok medtem ko myNode ohrani svoje reference. Kakorkoli, tako bo pa delalo: theNode = GenerateRandomNode("new node value") If myNode.left.value = nekNiz Then myNode.left = theNode ElseIf myNode.middle.value = nekNiz Then myNode.middle = theNode ElseIf myNode.right.value = nekNiz Then myNode.right = theNode End If