C# - Kontrollera om parenteser är balanserade

Permalänk
Inaktiv
Skrivet av CyberVillain:

Det är onödigt komplext om du istället bara räknar upp ett för ( och minus ett för ) så slipper du massor med kod, se mitt exempel ovan

Då det var en del av uppgiften spelar det inte så stor roll om det är mer eller mindre komplext.

@Lamposksk: Din kod krashar för du kollar på ett element som är null när du börjar med ')'

Permalänk
Medlem

Som sidkuriosa: Här är en lösning i Scala som använder sig av rekursion och pattern matching. Troligtvis tillräckligt mycket "pseudo" för att inte ge bort lösningen gratis

def isBalanced(input: String, depth: Int = 0): Boolean = input.splitAt(1) match { case ("", _) => depth == 0 case ("(", rest) => isBalanced(rest, depth + 1) case (")", rest) => depth > 0 && isBalanced(rest, depth - 1) case (_, rest) => isBalanced(rest, depth) } isBalanced("(apa)") //> res0: Boolean = true isBalanced("(())") //> res1: Boolean = true isBalanced("(kalle)olle(pelle)") //> res2: Boolean = true isBalanced("") //> res3: Boolean = true isBalanced(")(((((((((((((((((") //> res4: Boolean = false isBalanced("())") //> res5: Boolean = false isBalanced("())(") //> res6: Boolean = false

Dold text

Jag tänker att detta kan vara intressant för de som främst sitter med Java/PHP/C# eller liknande. Pattern matching och rekursion lämpar sig väldigt bra för att dekonstruera simpla rekursiva strukturer.

Visa signatur

Kom-pa-TI-bilitet

Permalänk

@anon81912: Haha, nu är jag riktigt jobbig. Men iaf, jag fixade det problemet och nu återstår ett problem och det är att när jag skriver ()( och ()) så står det ändå rätt.

Nya koden:

private void btnKontrollera_Click(object sender, EventArgs e) { Stack<char> Källkod = new Stack<char>(); string Parentes = tbxParentes.Text; foreach (char A in Parentes) { if (Parentes == "(") { Källkod.Push(A); } if (Parentes == ")") { if (Källkod.Count() == 0) { lblUtskrift.Text = "Fellllll"; } else { Källkod.Pop(); } } if (Källkod.Count() > 0) { lblUtskrift.Text = "Fel2"; } else { lblUtskrift.Text = "Rätt"; } } } } }

Permalänk
Medlem

Dina if:ar går ju mot Parentes och inte A så det där kan omöjligen bli rätt...

Permalänk
Skrivet av Lamposksk:

@Killbom: Haha, nu är jag riktigt jobbig. Men iaf, jag fixade det problemet och nu återstår ett problem och det är att när jag skriver ()( och ()) så står det ändå rätt.

Nya koden:

private void btnKontrollera_Click(object sender, EventArgs e) { Stack<char> Källkod = new Stack<char>(); string Parentes = tbxParentes.Text; foreach (char A in Parentes) { if (Parentes == "(") { Källkod.Push(A); } if (Parentes == ")") { if (Källkod.Count() == 0) { lblUtskrift.Text = "Fellllll"; } else { Källkod.Pop(); } } if (Källkod.Count() > 0) { lblUtskrift.Text = "Fel2"; } else { lblUtskrift.Text = "Rätt"; } } } } }

Som den före sa, och en sak till, dina två sista utskrifter kommer göras varje varv i din foreach som det ser ut nu. Fundera på om det verkligen är det du vill den ska göra.

Visa signatur

Corsair Vengeance LPX 4x8GB DDR4 2666MHz CL16 | Intel Core i7 6700 3,4 GHz 8MB | MSI Z170A KRAIT GAMING | Corsair Force Series 3 120 GB | Seagate SSHD Desktop 2 TB 7200 RPM 3,5" | Creative Sound Blaster Z PCIe | Western Digital 500 GB | Samsung Writemaster | Corsair TX750 V2 750 W | EVGA GeForce GTX 970 4GB SSC ACX 2.0+| Fractal Design Define R5 (Svart)

Permalänk

@BasseBaba: Va?

if (Parentes == "(")
{
Källkod.Push(A);

}

if (Parentes == ")")
{

Du menar alltså att jag ska byta ut Parentes mot A där? Det går inte? Och det blir inte logiskt rätt?

Permalänk

@RedRetro: Gjorde EXAKT som du skrev och det funkar fortf inte, (), ()() och (()) funkar, vilket är bra men när jag skriver ()( står det att det blir rätt

private void btnKontrollera_Click(object sender, EventArgs e) { Stack<char> Källkod = new Stack<char>(); string Parentes = tbxParentes.Text; foreach (char A in Parentes) { if (Parentes == "(") { Källkod.Push(A); } if (Parentes == ")" && Källkod.Count() > 0) { Källkod.Pop(); } } if (Källkod.Count() > 0) { lblUtskrift.Text = "Fel"; } else { lblUtskrift.Text = "Rätt"; } } } }

Permalänk
Medlem
Skrivet av Lamposksk:

@RedRetro: Gjorde EXAKT som du skrev och det funkar fortf inte, (), ()() och (()) funkar, vilket är bra men när jag skriver ()( står det att det blir rätt

Stack<char> Källkod = new Stack<char>(); string Parentes = tbxParentes.Text; foreach (char A in Parentes) { if (Parentes == "(") { Källkod.Push(A); } if (Parentes == ")" && Källkod.Count() > 0) { Källkod.Pop(); } } if (Källkod.Count() > 0) { lblUtskrift.Text = "Fel"; } else { lblUtskrift.Text = "Rätt"; }

Du är nära...

Stack<char> Källkod = new Stack<char>(); string Parentes = ")()()("; foreach (char A in Parentes) { if (A == '(') // char i c# skrivs med ' medans string skrivs med " { Källkod.Push(A); } else if (A == ')') // char i c# skrivs med ' medans string skrivs med " { if (Källkod.Count > 0) { Källkod.Pop(); } else // Vi försöker stänga en parentes, men ingen är öppen, dvs koden "kompilerar" inte. { Källkod.Push('x'); // Ett dummy-värde för att Källkod.Count inte ska vara 0. break; // Vi avbryter loopen. } } } if (Källkod.Count == 0) { Console.Write("Rätt"); } else { Console.Write("Fel"); }

Skrivet av RedRetro:

@sickhouse - Tråkigt att du lämnade ut den rätta lösningen. Det är uppenbart att TS fortfarande inte har förståelse för lösningsidéen. Hade han förstått sig på sättet som vi beskrivit att han skall lösa uppgiften på, hade han utan problem kunnat lista ut det där. Och om du nu tvunget skall lämna ut lösningen, förklara åtminstone varför koden ser ut som den gör och var TS tänkte fel. Annars blir det bara copy-paste vilket inte leder till någon förståelse.

Min tanke var mest att TS lösning innehöll slarvfel, men du kanske har rätt. TS kanske inte har någon som helst aning vad det är för skillnad på en char eller string. TS kanske borde göra betydligt mer basic uppgifter ur sin bok... Om inte annat kan TS släppa det här nu och träna på datatyper och foreach-loopar :). (Editade in lite kommentarer)

Permalänk
Medlem
Skrivet av Lamposksk:

@RedRetro: Gjorde EXAKT som du skrev och det funkar fortf inte, (), ()() och (()) funkar, vilket är bra men när jag skriver ()( står det att det blir rätt

private void btnKontrollera_Click(object sender, EventArgs e) { Stack<char> Källkod = new Stack<char>(); string Parentes = tbxParentes.Text; foreach (char A in Parentes) { if (Parentes == "(") { Källkod.Push(A); } if (Parentes == ")" && Källkod.Count() > 0) { Källkod.Pop(); } } if (Källkod.Count() > 0) { lblUtskrift.Text = "Fel"; } else { lblUtskrift.Text = "Rätt"; } } } }

Det verkar som att du fortfarande inte själv förstår hur du skall lösa uppgiften, utan endast försöker följa våra lösningsförslag. Jag tänker inte ge dig hela lösningen, utan försökte guida dig på rätt väg. Om du hade förstått lösningsidéen hade du också förstått vad som är fel. Kika på det fetmarkerade. Besvara följande frågor: Vilka villkor kollar du på, varför kollar du på just dessa villkor, vad skall du göra om dessa villkor inte är uppfyllda?

Tips: Du behöver inte kolla båda villkoren samtidigt.

EDIT:

@hultron - Tråkigt att du lämnade ut den rätta lösningen. Det är uppenbart att TS fortfarande inte har förståelse för lösningsidéen. Hade han förstått sig på sättet som vi beskrivit att han skall lösa uppgiften på, hade han utan problem kunnat lista ut det där. Och om du nu tvunget skall lämna ut lösningen, förklara åtminstone varför koden ser ut som den gör och var TS tänkte fel. Annars blir det bara copy-paste vilket inte leder till någon förståelse.

Visa signatur

Citera för svar!

Stationär: Fractal Design Define R6 | Asus Z370-P | Intel i7 8700k @ 3.7 Ghz | Corsair Vengeance LPX 32GB CL15 @ 3000 Mhz | Asus STRIX GTX960 4GB | Fractal Design Celsius S24 | 5 TB HDD | 250GB SSD (Samsung 850 EVO), 128GB SSD (Crucial M4) | Corsair HX 850W | W10
Bärbar: Sony Vaio Pro 13.3" | i7-4500U | 8GB RAM | 256GB SSD | Ubuntu

Permalänk
Medlem
Skrivet av Lamposksk:

@BasseBaba: Va?

if (Parentes == "(")
{
Källkod.Push(A);

}

if (Parentes == ")")
{

Du menar alltså att jag ska byta ut Parentes mot A där? Det går inte? Och det blir inte logiskt rätt?

Du kanske skulle börja med lite enklare utskrifter så du får en förståelse för t ex din foreach-loop:
https://dotnetfiddle.net/Widget/myB7P5

Skrivet av hultron:

Du är nära...

Jag skulle inte kalla det nära när killen knappt förstår skillnaden mellan "Parentes" och "A" i sin loop.

Permalänk
Datavetare

@Teknocide: gillar helt klart (svans)rekursiva lösning, problemet är bara att de kan ha otrevliga överraskning i språk/plattformar som inte garanterar att optimera bort svansrekursion (som t.ex. JVM (Java,Scala) och CLR (C#)).

Som du skrivit koden nu så kommer moderna versioner av den "vanliga" scala-kompilatorn utföra "tail-call optimization" och alla typer av strängar är "safe". Men lite lagom ologisk så kommer det smälla med java.lang.StackOverFlowError på en del input (väldigt högt djup, ~1000 på 32-bit och ~10000 på 64-bit) om man i stället råkar ha samma kod i en metod på ett objekt.

Nu kan det i.o.f.s. smälla även med en imperativ lösning baserade på en explicit stack, men det händer först när man helt enkelt inte har nog med RAM att hantera alla '('. Det rekursiva lösningen smäller långt innan, framförallt på 32-bitsystem.

Finns i.o.f.s språk som garanterar optimering svansrekursion (t.ex. Haskell och Clojure om man explicit använder recur) och språk där stacken växer dynamiskt vid behov (t.ex. Go och Erlang), där är det "safe" men en sådan lösning även i produktionskod.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer