Yığınla ifade işlemleri: parantez, infix → postfix, postfix hesaplama
Parantez dengesini kontrol etmek, infix ifadeyi öncelik kurallarıyla postfix'e çevirmek ve postfix ifadeyi yığınla hesaplamak. Sınavda adım adım yığın tablosu çizdirilir.
Hesap makinesine 2 + 3 * 4 yazınca 14 alırsın, 20 değil. Makine öncelik kurallarını nasıl uygular? Cevap: iki yığın algoritması. Önce ifadeyi parantezsiz bir biçime (postfix) çevirir, sonra o biçimi soldan sağa tek geçişte hesaplar. Aynı yığın fikri editörlerin parantez eşleştirmesinde de kullanılır. Sınavda üç soru tipi var: dengeli mi, postfix’e çevir (çoğu zaman yığın tablosuyla), postfix’i hesapla.
Altın kurallar:
- Açılan son parantez ilk kapanmalı. Yığın tam bunu kontrol eder.
- Postfix’te işlenenlerin (operand) sırası değişmez. Sadece operatörler yer değiştirir.
- Yüksek öncelikli operatör yığından önce çıkar.
- Postfix hesaplarken ilk çekilen sağ işlenendir.
Parantez dengesi (balanced parentheses)
Algoritma: soldan sağa oku. Açılış parantezini it. Kapanış gelince yığın boşsa ya da tepedeki açılış aynı türde değilse dengesiz. Sonda yığın boş değilse dengesiz.
static boolean isBalanced(String s) {
Deque<Character> st = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') st.push(c);
else if (c == ')' || c == ']' || c == '}') {
if (st.isEmpty()) return false;
char open = st.pop();
if ((c == ')' && open != '(') || (c == ']' && open != '[') || (c == '}' && open != '{'))
return false;
}
}
return st.isEmpty();
}
{[()()]} -> true
([)] -> false
(() -> false
())( -> false
{[]}() -> true
a*(b+c] -> false
Her karakterden sonra yığının hali (soldan sağa: dip → tepe):
input: ( [ ] { } )
( stack(bottom->top): (
[ stack(bottom->top): ([
] stack(bottom->top): (
{ stack(bottom->top): ({
} stack(bottom->top): (
) stack(bottom->top): (empty)
end: empty -> balanced
TUZAK · Sayı tutmak yetmez. “Açılış sayısı = kapanış sayısı” kontrolü
([)]için evet der ama ifade yanlış.)(için de sayı eşit ama sıra yanlış. Tür ve sıra için yığın şart.
Üç gösterim: infix, postfix, prefix
| Gösterim | Örnek | Açıklama |
|---|---|---|
| infix | A + B * C | operatör ortada, insan dili; parantez ve öncelik gerekir |
| postfix | A B C * + | operatör işlenenlerden sonra; parantez gerekmez |
| prefix | + A * B C | operatör işlenenlerden önce |
Postfix’e Reverse Polish Notation (RPN) da denir. Avantajı: öncelik bilgisi sıranın içine gömülüdür, makine soldan sağa okuyup tek yığınla hesaplar.
Elle çevirmenin hızlı yolu: ifadeyi tamamen parantezle, sonra her operatörü kendi kapanış parantezinin yerine taşı. A + B * C → (A + (B * C)) → A B C * +.
İnfix → postfix algoritması
Bir çıktı dizgisi ve bir operatör yığını kullanılır.
Her token için:
işlenen (harf/sayı) → çıktıya yaz
( → yığına it
) → ( gelene kadar pop edip çıktıya yaz; ( 'ı at
operatör op → yığın boş değil, tepe ( değil VE
[ prec(tepe) > prec(op) ya da prec(tepe) == prec(op) ve op sola bağlı ]
olduğu sürece pop edip çıktıya yaz; sonra op'u it
Sonda: yığında kalanları pop edip çıktıya yaz
| Operatör | Öncelik | Bağlanma (associativity) |
|---|---|---|
^ | 3 | sağdan sola |
* / % | 2 | soldan sağa |
+ - | 1 | soldan sağa |
Java kodu (tek harfli işlenenler için):
static int prec(char op) {
switch (op) {
case '+': case '-': return 1;
case '*': case '/': case '%': return 2;
case '^': return 3;
}
return 0;
}
static String toPostfix(String infix) {
StringBuilder out = new StringBuilder();
Deque<Character> st = new ArrayDeque<>();
for (char c : infix.toCharArray()) {
if (c == ' ') continue;
if (Character.isLetterOrDigit(c)) out.append(c);
else if (c == '(') st.push(c);
else if (c == ')') {
while (st.peek() != '(') out.append(st.pop());
st.pop(); // ( at
} else {
while (!st.isEmpty() && st.peek() != '(' &&
(prec(st.peek()) > prec(c) || (prec(st.peek()) == prec(c) && c != '^')))
out.append(st.pop());
st.push(c);
}
}
while (!st.isEmpty()) out.append(st.pop());
return out.toString();
}
Çözümlü iz: A + B * C - D / E
token stack output
A (empty) A
+ + A
B + AB
* +* AB
C +* ABC
- - ABC*+
D - ABC*+D
/ -/ ABC*+D
E -/ ABC*+DE
end (empty) ABC*+DE/-
Kritik an - token’ı: tepede * (öncelik 2 > 1) var, çıkar. Sonra tepede + (eşit öncelik, soldan sağa) var, o da çıkar. Ancak ondan sonra - itilir. / geldiğinde tepedeki - daha düşük öncelikli olduğu için kalır.
Program bir dizi ifadeyi çevirdi:
A+B*C -> ABC*+ maxStack=2
(A+B)*C-D -> AB+C*D- maxStack=2
A*(B+C)/D-E -> ABC+*D/E- maxStack=3
A-B-C -> AB-C- maxStack=1
A^B^C -> ABC^^ maxStack=2
(A+B)*(C-D) -> AB+CD-* maxStack=3
A+B*(C^D-E)^(F+G*H)-I -> ABCD^E-FGH*+^*+I- maxStack=6
maxStack, çevirme sırasında yığının ulaştığı en büyük boyuttur; sınavda bazen sorulur.
TUZAK · Sağa bağlı
^. matematikte demektir. Eşit öncelikte^geldiğinde tepedeki^’ı çıkarırsanAB^C^yazarsın, bu olur. DoğrusuABC^^.
Postfix ifadeyi hesaplama
Bu sefer yığında sayılar var.
Her token için:
sayı → it
operatör → right = pop(), left = pop(), it(left op right)
Sonda yığında tek sayı kalır: sonuç
static int evalPostfix(String expr) {
Deque<Integer> st = new ArrayDeque<>();
for (String tok : expr.trim().split("\\s+")) {
if (tok.matches("-?\\d+")) st.push(Integer.parseInt(tok));
else {
int right = st.pop();
int left = st.pop();
switch (tok) {
case "+": st.push(left + right); break;
case "-": st.push(left - right); break;
case "*": st.push(left * right); break;
case "/": st.push(left / right); break;
}
}
}
return st.pop();
}
Çözümlü iz: 4 7 2 - * 3 +
Her token sonrası yığın (dip → tepe):
4 4
7 4 7
2 4 7 2
- 4 5
* 20
3 20 3
+ 23
23
Kontrol: postfix’i infix’e geri çevir. 7 2 - = (7 − 2), 4 (7−2) * = 4 · 5, 20 3 + = 23. Doğru.
İPUCU · Operand sırası.
9 5 - 2 -için doğru sonuç (9 − 5) − 2 = 2. pop sırasını ters alırsan önce 5 − 9 = −4, sonra 2 − (−4) = 6 bulursun. “İlk çıkan sağa gider” cümlesini ezberle.
Hatalı ifade tespiti: bir operatör geldiğinde yığında iki sayı yoksa ya da sonda birden fazla sayı kalıyorsa ifade bozuktur (3 + gibi).
Sık yapılan hatalar
| Yanlış | Doğrusu |
|---|---|
| Parantezde sadece sayı kontrolü | Tür ve sıra için yığın; sonda boş olmalı |
| Postfix’te işlenen sırasını değiştirmek | A B C sırası korunur, sadece operatörler taşınır |
) gelince (’ı çıktıya yazmak | Parantezler çıktıya hiç girmez |
Eşit öncelikli operatörü yığında bırakmak (A-B-C → ABC--) | Sola bağlıysa çıkar: AB-C- |
^ için de eşitte çıkarmak | Sağa bağlı: ABC^^ |
| Sonda yığını boşaltmayı unutmak | Kalan operatörler tepeden sırayla çıktıya |
Hesaplarken pop() - pop() | right = pop(); left = pop(); left - right |
Operatörden önce ( kontrolü yapmamak | Tepe ( ise dur, ( sadece ) ile çıkar |
Kendini test et
Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.
Using the stack algorithm, which of these strings are balanced? (a) {[()()]} (b) ([)] (c) (() (d) {[]}()
Cevabı göster
(a) her kapanış tepedeki açılışla eşleşir, sonda yığın boş. (b) ) geldiğinde tepede [ var: uyumsuz. (c) Sonda yığında bir ( kalır. (d) iki ayrı dengeli grup, sonda boş.
The string { [ ( ) ] ( } is checked with a stack. What does the stack contain (bottom → top) just before the last character is read, and why does the check fail?
Cevabı göster
{ → {, [ → {[, ( → {[(, ) → {[, ] → {, ( → {(. Son karakter } tepedeki ( ile eşleşmez, dengesiz.
Convert to postfix: A + B * C
Cevabı göster
* önceliği +'dan yüksek. + yığına girer, B'den sonra gelen * onu çıkarmaz, üstüne girer. Sonda yığın tepeden boşaltılır: önce *, sonra +. Çıktı ABC*+.
Convert to postfix: (A + B) * C - D
Cevabı göster
Parantez içi önce: AB+. Sonra * girer, C yazılır. - geldiğinde tepedeki * daha yüksek öncelikli, çıkar. Sonra D, en sonda -. Çıktı AB+C*D-.
Convert to postfix: A * (B + C) / D - E
Cevabı göster
* girer. ( girer, B, +, C. ) gelince + çıkar: ABC+. / gelince tepedeki * aynı öncelikte ve soldan sağa olduğundan çıkar: ABC+*. D yazılır. - gelince / çıkar. E, sonda -. Yığının en fazla 3 eleman tuttuğu an: * ( +.
Convert to postfix: (a) A - B - C (b) A ^ B ^ C, where ^ is right-associative.
Cevabı göster
(a) - soldan sağa: (A − B) − C. İkinci - geldiğinde tepedeki eşit öncelikli - çıkar: AB-C-. (b) ^ sağdan sola: A ^ (B ^ C). Eşit öncelikteki ^ çıkarılmaz, üstüne itilir; sonda ikisi birden çıkar: ABC^^. Kural: eşit öncelikte sola bağlıysa çıkar, sağa bağlıysa çıkarma.
Evaluate the postfix expression: 5 3 + 2 *
Cevabı göster
5, 3 itilir. +: 3 ve 5 çekilir, 8 itilir. 2 itilir. *: 8 · 2 = 16.
Evaluate the postfix expression and show the stack after each token: 6 2 3 + - 3 8 2 / + *
Cevabı göster
6 6
2 6 2
3 6 2 3
+ 6 5
- 1 (6 - 5)
3 1 3
8 1 3 8
2 1 3 8 2
/ 1 3 4 (8 / 2)
+ 1 7
* 7İnfix karşılığı (6 − (2 + 3)) · (3 + 8 / 2) = 1 · 7 = 7.Evaluate: 8 2 / 3 - 4 2 * +. Careful with the operand order for - and /.
Cevabı göster
8 2 / → 8 / 2 = 4. 4 3 - → 4 − 3 = 1. 4 2 * → 8. 1 8 + → 9. Operatörde ilk çekilen sağ işlenendir: right = pop(); left = pop(); left - right. Ters yaparsan 2 / 8 = 0 ve 3 − 4 = −1 gibi yanlış sonuçlar çıkar.
Write static boolean isBalanced(String s) that checks (), [] and {} using a stack. Other characters are ignored.
Cevabı göster
static boolean isBalanced(String s) {
Deque<Character> st = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') {
st.push(c);
} else if (c == ')' || c == ']' || c == '}') {
if (st.isEmpty()) return false; // fazladan kapanış
char open = st.pop();
if ((c == ')' && open != '(') ||
(c == ']' && open != '[') ||
(c == '}' && open != '{')) return false; // tür uyumsuz
}
}
return st.isEmpty(); // açık kalan var mı
}Üç hata türü: ())( (boşken kapanış), ([)] (tür uyumsuz), (() (sonda dolu). a*(b+c] → false.Write static int evalPostfix(String expr) for space-separated integer tokens and the operators + - * /.
Cevabı göster
static int evalPostfix(String expr) {
Deque<Integer> st = new ArrayDeque<>();
for (String tok : expr.trim().split("\\s+")) {
if (tok.matches("-?\\d+")) {
st.push(Integer.parseInt(tok));
} else {
int right = st.pop(); // önce SAĞ
int left = st.pop();
switch (tok) {
case "+": st.push(left + right); break;
case "-": st.push(left - right); break;
case "*": st.push(left * right); break;
case "/": st.push(left / right); break;
}
}
}
return st.pop();
}4 7 2 - * 3 + → 4 · (7 − 2) + 3 = 23. Hatalı ifadede (3 +) ikinci pop boş yığında NoSuchElementException fırlatır.Convert A * (B - C) + D to postfix and give the operator stack (bottom → top) right after the token ) is processed and right after + is processed.
Cevabı göster
token stack output
A (empty) A
* * A
( *( A
B *( AB
- *(- AB
C *(- ABC
) * ABC-
+ + ABC-*
D + ABC-*D
end (empty) ABC-*D+) gelince ('a kadar her şey çıkar (-), ( atılır. + gelince tepedeki * daha yüksek öncelikli, çıkar; sonra + itilir.Doğrulama: Parantez kontrolü, infix → postfix çevirici ve postfix hesaplayıcı verify/SEN2211/W06.java içinde yazıldı ve JDK ile çalıştırıldı (java W06.java). Sayfadaki iz tabloları programın her token sonrası yazdırdığı yığın ve çıktı satırlarından birebir alındı; postfix sonucu aynı infix ifadesinin Java'da doğrudan hesabıyla (7) karşılaştırıldı.