Új hozzászólás Aktív témák
-
Azazel999
csendes tag
válasz
kingabo #1999 üzenetére
Sikerült!
Ez lett a vágás metódus:
Fa* Fa::vag(Fa* v_pont){
vector<Fa*> kicsik;
vector<Fa*> nagyok;
Fa *aktualis = this, *kovetkezo;
//fa szétdarabolása
int count = 0;
while (aktualis->kulcs != v_pont->kulcs){
if (aktualis->kulcs < v_pont->kulcs){
kicsik.push_back(aktualis);
kovetkezo = aktualis->jobb;
aktualis->jobb->apa = NULL;
aktualis->jobb = NULL;
cout << "jobbra" << endl;
} else if (aktualis->kulcs > v_pont->kulcs){
nagyok.push_back(aktualis);
kovetkezo = aktualis->bal;
aktualis->bal->apa = NULL;
aktualis->bal = NULL;
cout << "balra" << endl;
}
aktualis = kovetkezo;
}
cout << "kint vagyok a ciklusbol" << endl;
//vágási elem gyrekeinek levágása
if (aktualis->bal != NULL){
cout << "vagasi_pontnak bal fia van" << endl;
kicsik.push_back(aktualis->bal);
aktualis->bal->apa = NULL;
aktualis->bal = NULL;
}
if (aktualis->jobb != NULL){
cout << "vagasi_pontnak jobb fia van" << endl;
nagyok.push_back(aktualis->jobb);
aktualis->jobb->apa = NULL;
aktualis->jobb = NULL;
}
cout << "vagasi pont gyerekei levagva" << endl;
vector<Fa*>::const_iterator iter;
//a kisebb- és nagyobb fa felépítése
for(int i = 1; i < kicsik.size(); ++i){
cout << "kisfa" << endl;
kicsik.at(0)->beszur(kicsik.at(i));
//kicsik.at(i)->kiir();
}
for(int j = 1; j < nagyok.size(); ++j){
cout << "nagyfa" << endl;
nagyok.at(0)->beszur(nagyok.at(j));
//nagyok.at(j)->kiir();
}
//a vágási pont gyökérré tétele, a két fa ráakasztása
v_pont->bal = kicsik.at(0);
v_pont->jobb = nagyok.at(0);
v_pont->bal->apa = v_pont;
v_pont->jobb->apa = v_pont;
//v_pont->kiir();
return v_pont;
}Bocs, ha nem volt egyértelmű a megfogalmazás, igyekeztem részletesen körülírni. Németh Tamás (SZTE-n tanít) honlapján az alga II. előadásfóliák között ott ez az önszervező bináris keresőfa (nem tudom, hogy szabad-e linkelni ide, ezért nem teszem). Ott folyamatábrával szemlélteti is, az sokkal érthetőbb, mint az én makogásom. Egyébként igazad lehet a rekurzióval, valószínűleg sokkal egyszerűbb lenne vele, de én már ennek is örülök. Ezt a metódust meg kell hívni a fa gyökerére, és a visszaadott érték lesz az új fa.
-
Azazel999
csendes tag
válasz
Azazel999 #1996 üzenetére
Nos, erre jutottam, de futtatáskor a vektoromból kifutok a számlálással valamiért:
void Fa::vag(Fa* v_pont){
vector<Fa*> kicsik;
vector<Fa*> nagyok;
Fa *aktualis = this, *kovetkezo;
//fa szétdarabolása
while (aktualis->kulcs != v_pont->kulcs){
if (aktualis->kulcs < v_pont->kulcs){
kicsik.push_back(aktualis);
kovetkezo = aktualis->jobb;
aktualis->jobb->apa = NULL;
aktualis->jobb = NULL;
} else if (aktualis->kulcs > v_pont->kulcs){
nagyok.push_back(aktualis);
kovetkezo = aktualis->bal;
aktualis->bal->apa = NULL;
aktualis->bal = NULL;
}
}
//vágási elem gyrekeinek levágása
if (aktualis->bal != NULL){
kicsik.push_back(aktualis->bal);
kovetkezo = aktualis->jobb;
aktualis->jobb->apa = NULL;
aktualis->jobb = NULL;
} else if (aktualis->jobb != NULL){
nagyok.push_back(aktualis->jobb);
kovetkezo = aktualis->bal;
aktualis->bal->apa = NULL;
aktualis->bal = NULL;
}
//a kisebb- és nagyobb fa felépítése
for(int i = 1; i < kicsik.size(); i++){
kicsik.at(0)->beszur(kicsik.at(i));
}
for(int j = 1; j < nagyok.size(); j++){
nagyok.at(0)->beszur(nagyok.at(j));
}
//a vágási pont gyökérré tétele, a két fa ráakasztása
v_pont->bal = kicsik.at(0);
v_pont->jobb = nagyok.at(0);
v_pont->bal->apa = v_pont;
v_pont->jobb->apa = v_pont;
} -
Azazel999
csendes tag
válasz
kingabo #1995 üzenetére
Szóval amit én tudok róla, az ez:
- Van egy egyszerű bináris keresőfának kinéző fánk
- Az elemei között fennálló relációk ennek megfelelőek (jobb gyerek kisebb, bal nagyobb)
- Legfeljebb két gyereke van egy elemnek
- Ezt a fát meg lehet vágni bármelyik pontjánál (értelemszerűen, ha gyökérbél vágjuk, önmagát adja majd vissza)
- A vágás így zajlik:
+ A keresés algoritmus szerint elindulunk a gyökértől a vágási pont (v_pont) felé
+ Ha v_pontnál kisebb elemet találunk, az "a" részfa lesz a neve (1 az első és i mindig nő eggyel)
+ Ha nagyobbat, akkor "b[j]" részfa lesz belőle (1 az első és j is mindig nő eggyel)
+ Minden lépésnél levágjuk az adott elemről azt a gyerekét, amelyik felé lépünk (nem lesz apja)
+ Ha elértük a v_pontot, akkor az előző két lépést végrehajtjuk a két gyerekére is (ha van neki)
+ Az a(i) fákat beszúrjuk a[1]-be egymás után sorrendben (i > 1)
+ b[j] fákat a b[1]-be (j > 1)
+a[1] és b[1] apja is v_pont lesz (ezért ők pedig a gyerekei)
+ véget érte az algoritmusHa rosszul tudnám, akkor valaki javítson ki, mert erre később is nagy szükségem lesz, ezért gáz, ha nem jól tudom.
Azért önszervező, mert ezt csinálja, ha "megvágod" és ugyanígy lehet beszúrni bele új elemet, csak ott luftot üt a keresés, és ott ér véget az algoritmus.
-
kingabo
őstag
válasz
Azazel999 #1994 üzenetére
Én ilyet nem tanultam, vagy nem rémlik. De ha ez ekkora művelet igénnyel jár, mint amit leírtál nem is csodálom. Szóval mit értesz önszerveződő bin kerfa alatt?
"Szóval tudom, minek kell történnie, ezt le is írtam."
Ha papíron le tudod játszani, akkor van kész algó. Miért nem írod le és segítünk lekódolni. -
Azazel999
csendes tag
válasz
kingabo #1992 üzenetére
Köszi, de ez nem AVL fa akar lenni, hanem konkrétan önszervező bináris keresőfa. Egyébként lehet, hogy a beszúrás, törlés metódusaim sem passzolnak hozzá :S Szóval tudom, minek kell történnie, ezt le is írtam. Nem ezzel van a baj, de nem tudom lekódolni. Tényleg sok próbálkozáson túl vagyok, de egyszerűen képtelen vagyok megoldani. Nem tudom, hogyan kódoljam le azt, hogy induljunk el a gyökértől kereséssel és nyisszantsunk le minden lépésnél a fából, majd a levágottakból gyúrjunk két fát, az egyikben a vágási pontnál kisebb, a másikban nagyobb elemekből és a két gyökér apja legyen a vágási pont.
-
kingabo
őstag
válasz
Azazel999 #1988 üzenetére
Ha jól sejtem Te avl fát akarsz implementálni: m. wiki, a. wiki, egyetemi jegyzet ebben, ha a matekos részeket kihagyod, sztem jó le van írva, képekkel. Csak pár pointert kell átállítani a forgatástól függően. Talán próbáld meg papíron, ott elvileg könnyebbnek kell lennie.
-
chabeee
aktív tag
sziasztok,
van egy feladatom ahol van több osztály is. egy lovag, egy zombi és ezekre örököltetve egy karakter.
a karakterben van egy int sebzes-em. ezzel a lovag és a zombi életerejét kell csökkenteni a tamadás menüpont alatt olyan módon, hogy amikor meghívjuk ezt a menupontot akkor a zombi életét a lovag sebzésével csökkentsük, a zombi "pedig válaszul 20%-os valószínűséggel vigyen be a saját sebzésének megfelelő sebzést a lovagnak". a sebez függvényem eddig van meg de nem tudom hogyan tudom levonni a zobmi életét.void karakter::fv_sebzes(karakter z, karakter s){
z.setEletero(z.getEletero() - sebzes);
if(!rand()%5){
s.setEletero(s.getEletero()-z.sebzes); // erre gondoltam de ez nem müxik
}
}valami ötlet?
(nem várok megoldást, inkább rávezetést, hogy milyen gondolkodás alapján csináljam, mert egyszerűnek hangzik de egyszerűen nem látom át)
előre is köszi,
csabi -
Azazel999
csendes tag
válasz
Azazel999 #1987 üzenetére
És közben rájöttem, hogy a "szétszedem őket két csoportba és egyenként beszúrom a két fába" ötlet nem jó, mivel ha más a sorrend, nem ugyanazok lesznek a részfák megfelelő részei, mint az eredetiek voltak, mert telejsen újakat épít belőlük. Szóval marad az átláncolás, de hogy a jó életbe lehet azt megcsinálni? Ha Java-ban egyszerűbb, úgy is elmagyarázhatjátok, de C++ az elsődleges célom, mivel abban magamtól is eljutottam idáig.
-
Azazel999
csendes tag
válasz
Jester01 #1986 üzenetére
Köszönöm, de nem ez volt a baj. Tökéletesen értem a pointereket (szerintem) és az, hogyan működnek. A problémám az, hogy nem tudom hogyan valósítsam meg a vágás/összeragasztás műveletét az önszervező bin.ker. fáknál. Tudom rá a szabályt, meg lerajzolom füzetben az egészet, de egyszerűen nem tudom lekódolni. Már tényleg sokféleképpen próbáltam.
-
Azazel999
csendes tag
Tudom, de már három órája nem kaptam választ és gondoltam jelzem, hogy még várok rá. Csak mert találkoztam már olyannal, hogy senki nem írt semmit, aztán mikor bepöccentem rajta, nagy flegmán közölték, hogy azért nem írtak, mert olyan egyszerű volt a kérdés, hogy szégyen még feltenni is.
-
Azazel999
csendes tag
Hahó, van itt valaki?
-
Azazel999
csendes tag
válasz
WonderCSabo #1978 üzenetére
Na jó, most már nagyon belekavarodtam. Tudnál adni valami támpontot az átláncoláshoz?
-
Azazel999
csendes tag
válasz
WonderCSabo #1978 üzenetére
Csak, hogy tisztázzuk, jól tudom-e a vágás szabályait:
- a vágási elem bal részfájában lesz minden, nála kisebb elem
- a jobb részfájában minden, nála nagyobb elemTehát, ha ő egy olyan elem volt, aki három szint mélyen van és még ilyen mélyen van neki jobb és bal részfája is, akkor nem tudom, csak úgy átláncolni, vagy igen?
-
Azazel999
csendes tag
válasz
WonderCSabo #1978 üzenetére
Ráadásul a beszúrással gondom akadt, mert elkezdtem írni a vágás metódust és rájöttem, hogy üres (vagyis NULL pointer) fába nem tud beszúrni ez a szerencsétlen.
-
Azazel999
csendes tag
válasz
WonderCSabo #1978 üzenetére
Átláncolom? Ezt most nem igazán értem.
A javas megoldás pedig továbbra is elképzelhetetlen számomra.
-
WonderCSabo
félisten
válasz
Azazel999 #1976 üzenetére
Nem értem, miért kéne hámoznod? Megfogod a részgát a gyökerénél fogva, és átláncolod. Ez "húzza" magával a többit is, minden alatta lévő elem hozzá van láncolva (már ha jó az implementációd).
Ja és természetesen javában is lehet láncolt adatszerkezeteket csinálni, mivel a java referenciákkal dolgozik...
-
Azazel999
csendes tag
válasz
Azazel999 #1976 üzenetére
Ja, és a kereső metódusban meg kell fordítani a kacsacsőröket, mert különben nem jól dolgozik:
Fa* Fa::keres(int kulcs){
if (this->kulcs == kulcs){
return this;
} else if (this->kulcs > kulcs){
return this->bal->keres(kulcs);
} else {
return this->jobb->keres(kulcs);
}
} -
Azazel999
csendes tag
válasz
Azazel999 #1975 üzenetére
Viszont a vágás megvalósításáról még lövésem sincs. Azt tudom, hogy kettévágom a fát két fává a vágási elem mentén. Az egyik fába kerülnek a nála kisebb elemeket tartalmazó részfák, a másikba a nála nagyobbak. Majd ő lesz az új fa gyökere és a két másik fát hozzácsapjuk bal-. és jobb leszármazottaknak. A hozzácsapással nincs is gond, az tulajdonképpen csak beszúrás, de hogyan hámozhatom ki az összes nála kisebb/nagyobb elemet, hogy aztán fát gyúrjak belőlük? Van erre valami bevált módszer?
-
Azazel999
csendes tag
Sziasztok!
C++-ban szeretnék készíteni egy önszervező bináris keresőfát (vagy Java-ban, de azzal elakadtam, mert pointerek nélkül nehézkes a dolog, szóval inkább C++). A vágás (vagyis a legfontosabb metódus
) még nincs meg, de azon kívül minden más igen (keresés, beszúrás, törlés, minimális/maximális elem, előző/ következő elem, teljes fa és egyetlen elem kiíratása). A problémám az, hogy bár a kód "szépen" néz ki és működnie is kéne, összeomlik, amikor keresek egy elemet. Már pedig ez nagyon nagy baj, mert a többi metódus szinte mind elemekre (részfa-gyökerekre) mutató pointereket kér paraméternek. Ebből adódóan egyik sem fut, mert nem tudok nekik pointert adni. Van egy Fa osztályom és egy Main állományom, ezek lennének:
Fa.cpp
#include "Fa.hpp"
#include <iostream>
#include <cstddef>
using namespace std;
Fa::Fa(){
this->kulcs = -1;
this->bal = NULL;
this->jobb = NULL;
this->apa = NULL;
}
Fa::Fa(int kulcs, Fa* bal, Fa* jobb, Fa* apa){
this->kulcs = kulcs;
this->bal = bal;
this->jobb = jobb;
this->apa = apa;
}
Fa::~Fa(){}
Fa::Fa(Fa& other){
this->kulcs = other.kulcs;
this->bal = other.bal;
this->jobb = other.jobb;
this->apa = other.apa;
}
Fa* Fa::keres(int kulcs){
if (this->kulcs == kulcs){
return this;
} else if (this->kulcs < kulcs){
return this->bal->keres(kulcs);
} else {
return this->jobb->keres(kulcs);
}
}
Fa* Fa::min(){
if (this->bal == NULL){
return this;
} else {
return this->bal->min();
}
}
Fa* Fa::max(){
if (this->jobb == NULL){
return this;
} else {
return this->jobb->max();
}
}
Fa* Fa::kovetkezo(){
if (this->jobb != NULL){
return this->jobb->min();
} else {
Fa* q = this->apa;
Fa* p = this;
while (q != NULL && p == q->jobb){
p = q;
q = p->apa;
}
return q;
}
}
Fa* Fa::elozo(){
if (this->bal != NULL){
return this->bal->max();
} else {
Fa* p = this->apa;
Fa* q = this;
while (q != NULL && p == q->bal){
p = q;
q = p->apa;
}
return q;
}
}
void Fa::beszur(/*Fa* fa, */Fa* beszurando){
Fa* y = NULL;
Fa* x = this;
while (x != NULL){
y = x;
if (beszurando->kulcs < y->kulcs){
x = x->bal;
} else {
x = x->jobb;
}
}
beszurando->apa = y;
if (y == NULL){
//fa = beszurando; //Ures volt a fa
} else {
if (beszurando->kulcs < y->kulcs){
y->bal = beszurando;
} else {
y->jobb = beszurando;
}
}
}
void Fa::torol(Fa* fa, Fa* torlendo){
Fa *x, *y;
if (torlendo->bal == NULL || torlendo->jobb == NULL){
y = torlendo;
} else {
y= torlendo->kovetkezo();
}
if (y->bal != NULL){
x = y->bal;
} else {
x = y->jobb;
}
if (x != NULL){
x->apa = y->apa;
}
if (y->apa = NULL){
fa = x;
} else if (y == y->apa->bal) {
y->apa->bal = x;
} else {
y->apa->jobb = x;
}
if (y != torlendo){
torlendo->kulcs = y->kulcs;
}
}
void Fa::kiir(){
cout << "kulcs: " << this->kulcs;
if (this->bal != NULL){
cout << " bal: " << this->bal->kulcs;
} else {
cout << " bal: NULL";
}
if (this->jobb != NULL){
cout << " jobb: " << this->jobb->kulcs;
} else {
cout << " jobb: NULL";
}
if (this->apa != NULL){
cout << " apa: " << this->apa->kulcs << endl;
} else {
cout << " apa: NULL" << endl;
}
if (this->bal != NULL){
this->bal->kiir();
}
if (this->jobb != NULL){
this->jobb->kiir();
}
}
void Fa::kiir_egyet(){
cout << "kulcs: " << this->kulcs;
if (this->bal != NULL){
cout << " bal: " << this->bal->kulcs;
} else {
cout << " bal: NULL";
}
if (this->jobb != NULL){
cout << " jobb: " << this->jobb->kulcs;
} else {
cout << " jobb: NULL";
}
if (this->apa != NULL){
cout << " apa: " << this->apa->kulcs << endl;
} else {
cout << " apa: NULL" << endl;
}
}Main.cpp
#include <iostream>
#include <cstddef>
#include <cstring>
#include "Fa.hpp"
using namespace std;
int main (int argc, char** argv){
//fa letrehozasa
Fa *fa = new Fa(5, NULL, NULL, NULL);
fa->beszur(new Fa(3, NULL, NULL, NULL));
fa->beszur(new Fa(4, NULL, NULL, NULL));
fa->beszur(new Fa(15, NULL, NULL, NULL));
fa->beszur(new Fa(2, NULL, NULL, NULL));
fa->beszur(new Fa(7, NULL, NULL, NULL));
cout << endl;
fa->kiir();
cout << "\n" << endl;
//cout << fa->keres(15)->kiir_egyet();
}Tudnátok adni valami tippet, hogy mi lehet a baj?
-
mgoogyi
senior tag
válasz
bandi0000 #1966 üzenetére
Szia,
Nekem az első gondolatom egy map, ahol a kulcs a kártya azonosítója (1,2, stb.), az érték meg az, hogy hány darab van belőle.
A map-be szépen beupdateeled, hogy miből mennyi van, aztán néhány állapotjelző kell csak, pl.
numOfPairs
numOfDrills
numOfPokers
, amiket a map alapján feltöltesszKét párnál a numOfPairs 2 lesz, egy full-nál a numOfPairs és numOfDrills 1-1.
Ezeket viszont muszáj végigcsekkolni esetekre bontva. -
-
-
bandi0000
nagyúr
hali
nagyon egyszerű feladatom vancsak ötletet gyüjtök
a lényeg az hogy csinálok 5 random számot ez meg van bele teszem egy tömbbe és lényegében a poker kártyák szerint kéne csoportosítani a számokat, tehát ha 1,1,1,3,4 a szám akkor kiirja hogy drill stb
még az menne hogy 1 számbol megnézem az egyformákat, de ha van több egyforma azt nem tudom hogyan vizsgáljam meg mentsem szóval 1,1,1,2,2 a számok ennél meg tudnám mondani hogy van egy drill, de ez nem jó mert ez egy full house -
VIC20
őstag
Lehet, hogy csak én nem találom, de ha 2010-es Visual Studióban új C++ projektet nyitok, akkor megcsinálja szépen az összes .h, .cpp, .ico állományt, ha elindítom, meg is jelenik egy üres ablak, menüvel, de nem látom sehol ezt formot, nem tudok rá vezérlőket tenni, mint Visual Basic-ben. (A toolbox azt mondja, hogy ,,There are no usable controls in this group (...)".)
-
ravenwood
csendes tag
valaki aki ért mesterséges intelligencia alap szintű programozásához RTS játékba az vegye fel velem privátba a kapcsolatot nem fogja megbánni
-
Jester01
veterán
válasz
bandi0000 #1959 üzenetére
Beolvasol egy teljes sort majd szétdarabolod. Egy egyszerű lehetséges megoldás (de nem túl hibatűrő):
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
int main(int, char**)
{
cout << "Enter numbers separated by spaces: ";
string line;
getline(cin, line);
istringstream s(line);
vector<int> numbers;
int x;
while(s >> x) numbers.push_back(x);
cout << "You entered " << numbers.size() << " numbers" << endl;
return 0;
} -
bandi0000
nagyúr
hali
Egy kis segítségre lenne szükségem
Az a feladat hogy függvényeket tanultuk és csinálni kellett 3 függvényt ami különböző műveleteket végez el ez meg is van de, úgy kell megoldani hogy be kell kérni 3 darab számot ha csak 1 számot írok akkor a program tudja hogy az első fügvényt kell végrehajtani ha 2 számot akkor a 2. ha 3 számot akkor a 3. függvényt, a függvények lényegében arról szólnak 1: 1 számmal kiszámolja a kör területét kerületét, 2: a 2 számmal kiszámolja egy téglalap területét kerületét, 3: 3 számmal a háromszög területét kerületét számolja kiSzóval azon gondolkoztam hogy hogy kéne megoldani ezt a szám bekérést mert arra már gondoltam hogy ha bekértem egy számmal egy if-el megvizsgálom hogy ha 1 szám van a tömbbe akkor csinálja az elsőt ha 2 a másodikat stb stb, csak ha jól tudom karakteressel lehetne bekérni és akkor ha jól tudom akkor belepakolja a tömbbe bármennyi számjegyet irok be de ez igy nem működik mert nem kap értéket
Van e valakinek valami ötlete hogy lehetne megoldani ezt??
Ja és természetesen a tanár annyit akar látni, hogy program lefut és beir 2 számot vagy 3 at vagy 1 et és csinálja, tehát nem jó az hogy bekérni az összes számot, vagy megkérdezni hogy melyik műveletet akarja csinálni stb -
VIC20
őstag
Sziasztok!
Kezdőként szeretnék tanácsot kérni: milyen fejlesztői környezetet ajánlanátok, ha Windows-ban (vagy valamilyen más ablakkezelős környezetben) szeretnék programozni (illetve először megtanulni).
Eddig Dev-C++-ban próbálkoztam (nem a régi Bloodshed-essel, hanem az újabb Orwell-el).
Korábban Visual Basic-et is használtam (na meg Pascal-t, de ez lényegtelen), ott a GUI tényleg nagyon kényelmes volt, az ember egérrel megtervezhette a form-ot, a GUI meg generálta hozzá a kódot. Létezik ilyen C++-hoz is? Vagy azonnal meg kell tanulni a Windows GUI programozását is? Ahhoz hol találni információt?
Előre is köszi!
-
proci985
MODERÁTOR
válasz
Perbalu #1954 üzenetére
az "ebben a témában mozog" eléggé tág megközelítésétől függően. google scholar / ACM / IEEE / scopus kezdésnek jó ha kutatási anyagok beszerzése a cél. ha interjú kell akkor meg érdemesebb maileket küldözgetni témába vágó cégeknek talán.
szvsz inkább a témavezetőd kérdezd.
-
Perbalu
csendes tag
Üdv!
Szakdolgozatomat most kezdem és tervbe van hogy lehetséges h vmilyen vst plugin (effect, torzito, visszhang stb) fejlesztése lenne a téma. Esetleg vki ismer olyat itt aki ebben a témában mozog?
mail: perbalu@freemail.hu
Thx -
44kos
csendes tag
válasz
sztanozs #1951 üzenetére
OK, de egyszerre egy helyen fut a program, nem? Azt írja a könyv, hogy amikor egy függvény meghívásához érkezik a program, miközben a main-ben fut, ott "felfüggesztődik", és odaugrik a meghívott függvényhez, és addig azt hajtja végre, amíg vissza nem tér onnan?
Hopp, miután ezt leírtam, megértettem.
Tehát elsőnek kiértékeli az Add(3,4)-et, ezért az Add() fv-ben lévő cout-ot végrehajtja(megjelenik az ottani szöveg), és ezután az x+y eredményével vissza is tér(de itt még nem tudja, hogy ezt ki kell majd írnia), és ugrik egyet balra, ahol az "A visszaadott érték" szerepel, és még 1-et ugrik balra, és mivel ott a cout parancsot kapja, kiteszi a kimenetre a mögötte álló részt, tehát olyan mintha a std::cout << "A visszaadott érték" << "7" ; parancs állna ott? -
sztanozs
veterán
Amikor meghívódik az Add() függvény, kiírja a képernyőre a szöveget, hogy Itt a az Add().... és ezután miért nem rögtön az eredményt, amivel visszatér írja ki, miért ékelődik be a függvény által kiírt szöveg és az eredmény(7) közé a "visszaadott érték" szöveg?
Azért, mert mivel az Add() nem értékelődött még ki, így az
std::cout << "A visszaadott érték: " << Add(3,4);
aláhúzott része még nem értékelődött ki, így még az egészstringstream nem került átadásra az stdoutra.
A << operátor miatt az aláhúzás sorrendjében történik a kiértékelődés (jobbról balra):
std::cout << "A visszaadott érték: " << Add(3,4);
std::cout << "A visszaadott érték: " << Add(3,4);
std::cout << "A visszaadott érték: " << Add(3,4); -
44kos
csendes tag
Sziasztok!
Most kezdtem el a programozni, elsőnek egy könyvön rágom át magamat, az egyik példájánál elakadtam:
A kérdésem a 12. sorhoz kapcsolódik, miért ez lesz az eredménye a kimeneten?A cout parancs jobbról balra értékelődne ki?
Azért kérdem, mert ha így is van, miért ebben a sorrendben írja ki a szöveget és a számot?
Amikor meghívódik az Add() függvény, kiírja a képernyőre a szöveget, hogy Itt a az Add().... és ezután miért nem rögtön az eredményt, amivel visszatér írja ki, miért ékelődik be a függvény által kiírt szöveg és az eredmény(7) közé a "visszaadott érték" szöveg? -
amargo
addikt
válasz
proci985 #1943 üzenetére
Persze megy azzal, csak nekem kicsit fura, mert 1x mindenképpen leakarod futtatni.
Qwertz_: Láttam a privátokat, de ha segítek itt teszem.
Ahhoz, hogy bármilyen gombra kilépjen, előbb be kell kérni azt.
Sok mindent nem értek ezzel a kóddal kapcsolatban, egy végtelen ciklusban szaladgálsz és mindenfélét próbálsz ott csinálni.
Ezzel pl mi a célod, főleg úgy, hogy a h és a w elsőnek 0:
// függőleges igazítás
for(i=1;i<h;i++)
cout << endl;
// vízszintes igazítás
for(i=1;i<w;i++)
cout << " ";
// szöveg kiírása
cout << s;
És azzal, hogy ezt végtelenszer végzed el? -
amargo
addikt
válasz
Qwertz_ #1939 üzenetére
Erre használják többek között a hatul tesztelő ciklusokat, ha csak túl akarsz lenni rajta, akkor használd a break-et.
-
Qwertz_
csendes tag
Sziasztok!
Remélem tudtok segíteni, nagyon hálás lennék!
Sehogyan nem tudom megoldani, hogy a következő program bármely gomb lenyomására lépjen ki:
#include <iostream>
#include <string>
#include <windows.h>
#include <conio.h>
#define H 25
#define W 80
using namespace std;
int main()
{
setlocale(LC_ALL, "hun");
string s;
int i;
// szöveg bekérése
cout << "Képernyővédő szövege:" <<endl;
cin >> s;
// h: x koordináta, w: y koordináta, hs: függőleges irány, ws: vízszintes irány
int h,w,hs,ws,a;
h=0;
w=0;
hs=1;
ws=1;
a=0;
fflush(stdin);
while (true)
{
// függőleges igazítás
for(i=1;i<h;i++)
cout << endl;
// vízszintes igazítás
for(i=1;i<w;i++)
cout << " ";
// szöveg kiírása
cout << s;
// maradék sorok kitöltése
for(i=0; i<H-h; i++)
cout << endl;
// következő pozíciók kiszámítása
h += hs;
w += ws;
// irányok beállítása a széleken
if (w == W-(s.size()))
ws = -1;
if (h == H-1)
hs = -1;
if(w == 0)
ws = 1;
if (h == 0)
hs = 1;
// késleltetés
Sleep(200);
}
return 0;
}Lenne szíves segíteni valaki?
-
-
Qwertz_
csendes tag
Üdv!
Valaki lenne szíves és megmondaná nekem, hogy miért nem működik a következő kód? Egyetlen hibát ír, de nem tudom, miért. #include <iostream>
#include <string>
#define H 21
#define W 80
using namespace std;
int main() {
string s;
cout << "Mi legyen a szoveg?" <<endl;
cin >> s;
int h=0, w=0, hs=1, ws=1;
while (true) {
for(int i=0;i<h;i++)
cout << endl;
for(int i=0;i<w; i++)
cout << " ";
cout << s;
for(int i=0; i<H-h; i++)
cout << endl;
h += hs;
w += ws;
if (w == W-(s.size()))
ws = -1;
if (h == H-1)
hs = -1;
if(w == 0)
ws = 1;
if (h == 0)
hs = 1;
usleep(5000);
}
} -
mgoogyi
senior tag
válasz
jattila48 #1933 üzenetére
Igazad lehet.
Valszeg jobb a konstruktor-ból hibát dobni, mint kétfázisúan inicializálni.
Viszont ha tényleg exception lehetséges a konstruktorban alapesetben, akkor már inkább elmennék a factory irányba, ami lekreálja az objektumot, visszaad rá egy pointert és azt nézheti a hívó fél, hogy NULL vagy sem.
Ebben az esetben a hívó félnek nem kell semmi meglepetésre számítania. -
jattila48
aktív tag
válasz
mgoogyi #1921 üzenetére
Ez így is van. A kliens felé biztosított init nem generál exceptiont, hanem bool-lal tér vissza. Viszont ez az init tagobjektumok init-jét hívja, amik generálhatnak exceptiont, de azok itt lekezelésre kerülnek.
Kontruktor-nak meg muszáj exceptiont generálni ha valami hiba történik, hiszen másképp nem tudja jelezni a hibát. A bad_alloc-ot lekezelheti (sőt!), de utána új exceptiont kell generálnia. -
scream
veterán
-
proci985
MODERÁTOR
pedig a kódrészletek darabonként próbálgatása ahol lehet tényleg sokat javít. sokkal egyszerűbb egy 20soros kódban megérteni pár dolgot, mint kapásból integrálni egy többszáz sorosba.
ha nem vagy biztos a pointerkezelésben és a függvényhívásokban, akkor különösen ajánlott először kipróbálni ezeket egy dummy vectoron, és csak utánna integrálni a véglegesbe.
gyakorlatilag hiába kell kétszer megírni a kódot, az ember időt nyer vele.
még egy tipp: használj értelmes változóneveket ha nem feladatkiírás (ha igen, akkor is megoldható a dolog), a numberOfClasses kissé beszédesebb, mint az M. (ha pedig nem lehet, használj angol változóneveket, későbbiekben a magyar változónevek akkor jók, ha a cég biztos nem akarja eladni a kódot országhatáron túlra)
-
mgoogyi
senior tag
Ez azért nehezen hihető, mert van olyan része a kódnak, ami nem fordul le.
Javítom a kódod és nemsokára felrakom pastebin-re. -
scream
veterán
-
mgoogyi
senior tag
válasz
pityaa23 #1923 üzenetére
Keress neten a házitokhoz hasonló feladatokat és próbáld megoldani.
+ kérdezz itt, ha van időm, válaszolok.Mindenképp értened kéne ezeket, majdnemhogy készségszinten:
for, while ciklusok
if, else if, else
pointerek, pl int *
referenciák pl. int &
new, new[], delete, delete[]
tömbök kezelése
class
{
private:
public:
protected:konstruktor
destruktoradattagok
tagfüggvények
virtual tagfüggvényekstatic adattagok
static függvényeköröklődés
}fontosabb collection-ök: std::set, vector, list
Mondjuk ez így elég sok, nem igazán két hetes téma.
Jó lenne tudni, hogy mi az, amit elvárnak. -
mgoogyi
senior tag
Bocs, nem akartalak megbántani, de ennyire nem fog egyszerűen menni a tanulás, csak kis lépésekben.
Elsőnek csak csinálj egy kisebb programot, ami beolvas valamit és kiírja a képernyőre.
2, beolvassas azokat a dolgokat, amikre szükséged lesz és azokat kiírja
3, a beolvasott dolgokat eltárolod valahogy, majd azokon végiglépkedve íratod ki
4, elkezdhetsz gondolkozni a többi dolgonA "biztató" szavak azért jöttek ki belőlem, mert a kódod túl sok hibát tartalmaz egyszerre és úgy tűnik, hogy nem probáltad ki az alapvető dolgokat, mint beolvasás, stb.
Meg kell küzdeni lépésenként mindennel. -
pityaa23
senior tag
válasz
mgoogyi #1910 üzenetére
Köszi!
Holnap tudok nekiállni. Eléggé amatőr vagyok. Későn kezdtem el foglalkozni vele. Programozás 1 tantárgyon túl vagyok, ami a struktúrákig tartott. Komolyabb dolgokat nem csináltunk. Most a programozás 2 eléggé nehezen megy, jó nagy különbség van nehézség terén a 2 tárgy között. Levelezőn tanulok, 3 hete volt az első óra, szóval nagyon idő se volt gyakorolgatni. Most yútúb videókat nézve kell tanulnom, mert az oktatás az kb annyi, hogy órán legépelünk egy programot, gondolkozni vagy önerő az nulla. Ezen a hétvégén vettük az osztályokat, de a fele anyagot le sem adták. Szuper. 15.-én Zh, addig szerintem minden időmet bele kell ölnöm, hogy összehozzak egy kettest. Házi egyébként a 2006 májusi emelt szintű programozás érettségi egyik feladata, csak ott ugye más nyelven írták.
Esetleg ha van ötletetek, hogyan tudnék gyorsan megtanulni programozni ne tartsátok magatokban!
-
scream
veterán
válasz
mgoogyi #1918 üzenetére
Sajnos még kezdő "programozó" vagyok, most tapasztalom ki mit hogyan kéne.
Mellesleg "csak" (
) félreértelmeztem, hogy mit is csinál a void paraméterlistája és nem voltak deklarálva az int mainben a dolgok, illetve a K-t &K-ként kell átadni és megy is.
"Most itt összehánytál egy csomó mindent, aztán halvány fingod sincs, hogy mi nem jó."
Köszönöm a biztató szavakat
-
mgoogyi
senior tag
válasz
jattila48 #1920 üzenetére
Úgy nézek ki, mint aki nem akar válaszolni?
- Az alapvető szabály (amennyire tudom), hogy ctor-ból és dtor-ból nem jöhet ki exception.
- Kétfázisú inicializálást meg akkor szoktak használni, amikor valamilyen hibakezelés szükséges, amit nem tehetünk meg a ctor-ban.Pl. mint amit te írsz, abban az esetben helytálló a dolog, hogy kétfázisú inicializálás kell. De ha veled kéne dolgoznom és csak az interface-ét látnám annak, amit használnom kell, akkor azt látnám, hogy az init visszatér egy bool-al, nyilván ez kéne, hogy jelezze, hogy sikerült-e az init. Ha teli kell raknom a kódot try - catch-el, mert mindenféle exception-re számítanom kell, akkor nem lesz nagy öröm használni az osztályodat.
És ha 1-nél többször kell használnom, amit csináltál, akkor már jobb, ha te try-catch-ezel az init-ben, az összes mindenki másnak, akik meg hívják az init függvényed, nekik meg elég a visszatérési értéket vizsgálniuk. -
jattila48
aktív tag
válasz
mgoogyi #1917 üzenetére
Biztosan meg lehet oldani másképp is ezt a problémát, pl. ahogy írod. Az én javaslatomnak az az előnye, hogy a konstruktorban nem kell kezelni az exceptiont, sőt az init tfv.-ben sem. Az init tfv. természetesen generálhat exceptiont, de azt lehet kezelni felsőbb szinten, és mikor az objektum kilép a scope-ból a destruktora (illetve a tagobjektumok destruktorai) automatikusan mindig elvegzik a deallokációt. Tehát bármilyen "mélyről" jön egy pointer tag inicializálásával keletkező exception, a végén minden sikeresen allokált pointer tag automatikusan felszabadul.
Nem mondtam, hogy ez lényeges kérdés, viszont szerintem érdekes. Ha nem akarsz, ne válaszolj rá! A kétfázisú inicializálást pedig sok tanulmány ellenzi. Keress rá! -
mgoogyi
senior tag
Mi a probléma konkrétan?
A függvény törzsébe nem tudod mit írj, vagy a paraméterlistájába?
Le se fordul?
Vagy ha elakad, hol akad el?Közben megpróbáltam lefordítani.
kivalogatas függvény:113.sor: string Mehetnek[N];
miért definiálod újra, ott van paraméterként
egyébként stack-en foglalt (nem írsz new-t) tömb esetén a tömbméret konstans kell legyen
(pl. const int N = 500 vagy #define N 500)114.sor: újradefiniálás megint, ha csak 0-ázni akarod, akkor elég a K = 0, de ekkor meg nincs értelme, hogy paraméter legyen
main:
33. sor: kivalogatas(N, M, Tanulok); - több, mint 3 paraméter kéne
34. sor: kiiras(); - nem hívhatod meg paraméterek nélkül, mert vannak paramétereibekeres:
89.sor: cin >> Tanulok.nev; - itt elsőre nem tom mi a baja, átírnám cin.getline-osra első próbálkozásképp
kiiras:
139.sor: cout <<"\n" <<" " << Mehetnek(i) <<endl; - itt sem értem miért nem kajolja be, egy .c_str() biztos megoldja
Összefoglalva:
Próbálj meg lépésenként haladni, és miután kipróbálsz(fordít,futtat, minden ok) egy kisebb dolgot, utána lépsz tovább.Most itt összehánytál egy csomó mindent, aztán halvány fingod sincs, hogy mi nem jó.
-
mgoogyi
senior tag
válasz
jattila48 #1913 üzenetére
Én még különösebb iránymutatást nem hallottam kétfázisú inicializálással kapcsolatban, pedig egy ideje már c++-ozok.
A ctor-os try catch dolog:
A felszabadítós dolgokat be lehet rakni egy függvénybe és azt hívod a ctor catch ágában és a dtor-ban is.
Na szóval az a véleményem, hogy ez nem egy lényeges kérdés. -
scream
veterán
Valaki tudna abban segíteni, hogy EBBEN a kódban miket kéne még beírni a voidokhoz, hogy rendesen menjen?
Már ezzel szenvedek és nem tudom miért nem akar menni.
-
jattila48
aktív tag
válasz
mgoogyi #1912 üzenetére
Így van, az auto_ptr nem jó tömbre.
Általában nem tanácsolják a kétfázisú inicializálást. Egy olyan helyzetet próbáltam mutatni, ahol mégiscsak célszerű lehet.
Ha a try cathc-et berakom a ctor-ba, ekkor a try-ban auto_ptr-t kéne használni, ami nem jó tömbre.
Az exception-nel az a problémám, hogy ha ctor-ban keletkezik, akkor nem fut le a destruktor (mivel ekkor nem lett teljesen megkonstruálva az objektum), és azok a felszabadítások amiket a destrukdornak kéne elvégezni, nem végződnek el. A kétfázisú inicializálás azon segít, hogy a destruktor mindenképp lefut (mivel a ctor nem dobott exceptiont, hiszen a kritikus inicializálást az init tfv. végzi), és elvégzi a nem NULL pointerek felszabadítását. A ctor-nak természetesen NULL-lal kell inicializálni a szóbanforgó pointereket.
Egyébként éppen tömb inicializálása kapcsán jött ez elő. Remélem így érthetőbb a dolog, persze felhajtást nem szeretnék csinálni, csak megbeszélni, kinek mi a véleménye. -
mgoogyi
senior tag
válasz
jattila48 #1911 üzenetére
- auto_ptr-rel nem tudsz tömböt felszabadítani (ha tudsz is róla, nem biztos, hogy mindenkinek egyértelmű, főleg mert char tömbökkel dolgozol)
- miért lenne baj a kétfázisú inicializálás? azt kell használni, ami célszerű az adott helyzetben.
- az exception dobás elkerülhető a new esetén az std::nothrow paraméterrel: new(std::nothrow), ekkor NULL pointer-t ad vissza a new, ha nem volt elég memória.
- a destruktorodnak muszáj az objektumod által lefoglalt dolgokat felszabadítani, ez nem kérdés. Nem értem ezt a nagy felhajtást.
- a try catchet ennyi erővel berakhatod a ctor-ba is, ha csak az exception a nagy problémád -
jattila48
aktív tag
Kétfázisú inicializálás az, amikor az objektumot a konstruktora nem inicializálja teljesen, hanem még egy inicializáló tfv.-t kell meghívni ahhoz, hogy az objektum használható legyen. Akkor szokták használni, ha az inicializálás során virtuális tfv.-t kell meghívni, vagy a konstruktor nem dobhat exception-t. A kétfázisú inicializálást általában kerülendőnek tekintik. Azonban szerintem kifejezetten hasznos is lehet, és nagyban egyszerűsítheti a megfelelő resource kezelést pl. memory leak elkerülésére használható. Ha pl. van egy objektumunk, aminek inicializálása során két memória foglalást végez, előfordulhat hogy az első allokáció sikeres, a második pedig nem. Konstruktorral megoldva ilyenkor auto_ptr-t használhatunk, mert az első pointert fel kell szabadítani, mielőtt a második allokáció sikertelensége miatt a konstruktor exception-t dob. Ilyenkor az objektum destruktora nem fut le, mert csak teljesen megkonstruált objektumra fut le a destruktor, ha az kilép a scope-ból. Na már most kétfázisú inicializálással az objektumot a konstruktora úgy hozza létre, hogy a szóban forgó két pointert NULL-lal inicializálja, majd az inicializáló tfv. elvégzi a szükséges allokációkat. Ha valamelyik allokáció nem sikerül, akkor az init tfv. exception-t dob, vagy false-val tér vissza, de a sikertelen allokáció eredményeként a pointer NULL marad. Az objektum destruktora csak a nem NULL pointert szabadítja fel, a NULL-t békén hagyja.
class A {
public:
A():c(NULL),d(NULL){}
~A();
bool init(int,int);
private:
char * c;
char *d;
}A::~A()
{
if(c!=NULL)delete[] c;
if(d!=NULL)delete[] d;
}bool A::init(int n,int m)
{
c=new char[n];
d=new char;
return true;
}void main(void)
{
try{
A a; //Ez mindenkepp lefut, nem dob exception-t
a.init(10,0x7fffffff); //A::d-nek tul nagy memoriat akarunk foglalni, ezert exception-t dob
}
catch(std::bad_alloc &){
std::cout << "Memory allpc error";
}
//Itt a lefoglalt A::c felszabadult, nincs memory leak
}A lényeg az, hogy a try blokk végén az A destruktora lefut, mert az A a objektum konstruktora mindenképp lefutott. Kicsit olyan ez, mintha az A osztály maga is egy "smart pointer" lenne.
Mit szóltok hozzá? Ugye nem is feltétlenül rossz a kétfázisú inicializálás? -
mgoogyi
senior tag
válasz
pityaa23 #1909 üzenetére
Csinálsz egy ehhez hasonló Aminosav osztályt:
Class Aminosav
{
private:
std::string rovidites;
char betujel;
int C,H,O,N,S;
const static int C_TOMEG = 12;
const static int *_TOMEG = ...
const static int *_TOMEG = ...
stb.
public:
Aminosav( >>paraméterek<< ) :
rovidites (p1),
betujel(p2),
stb.
{
}
std::string OsszegKeplet()
{
...
}
int RelativTomeg()
{
...
}
stb.
};Beolvasáskor valamilyen konténerbe(pl. std::set vagy std::vector) bepakolod őket a file-ból beolvasott adatok alapján.
Minden részfeladathoz csinálsz neki egy függvényt, és a függvényben megoldod a részfeladatot.
pl a relatív tömeg az egy súlyozott összeadás.Beolvasás: std::ifstream-mel például, a sorok parsolása meg tokenekre szedéssel vagy sscanf.
Az a kérdés, hogy milyen szinten vagy és mi nem világos abból, amit leírtam?
-
pityaa23
senior tag
Sziasztok!
Kaptam egy házit programozásból, linkelem is.
Feladat
aminosav.txt
bsa.txtszerk: visual studioban programozunk, C++ programnyelv.
Tudnátok adni ötleteket, hogy hogy kezdjek neki?
konkrétan az a bajom, hogy az aminosav txt-ből hogy tudnám valahogy rendezni vagy az adatokra konkrétan rákeresni. Gondolkoztam, hogy mivel minden sor \n végű így az alapján szét tudnám választani őket és tömbökbe rakni az egyes aminosavakat, innen talán már könnyebb lenne dolgozni velük. Ez lenne kb a 3.-ik feladatig.A 4. feladatban, meg kéne számolni a C, H, O, N, S betűket majd beszorozni egyenként az atomszámukkal gondolom? Bár nem értem azt a részt hogy az aminosavak összekapcsolódásakor kilép egy Hˇ2O molekula.
5.- Feladatban is mondjuk elkezdeném írni tömbbe a beolvasott adatokat, közben keresni kéne az Y vagy W vagy F betűket, és amint talált, egy új tömböt kezdenék? Ha ez megvan akkor a legnagyobb tömb lenne a megoldás, bár nem tudom hogy tudnám a láncban elfoglalt helyét így meghatározni.
6. Feladat. Itt is gyakorlatilag lehetne kezdeni úgy mint az ötösben, csak a keresésnél R majd A vagy R majd V -t talál akkor kezd új tömböt. Az első tömbben megszámolnám a C-betűket majd kiíratnám.
Kezdő vagyok, lehet sokkal egyszerűbben is meg lehetne oldani, nem tudom ezért is várnék némi ötletet ha tudtok! Határidőm December 8 reggel 8 óra a beadáshoz. Ha addig nem tudnám megoldani lehetne számítani valaki segítségére? Fontos lenne, akár egy évet is csúszhatok, ha nem lesz meg a tárgy sajnos...
Köszönöm mindenkinek előre is!
-
proci985
MODERÁTOR
vector<vector<int>> studentResults;
vector<int> competingStudents;
for(unsigned int i = 0; i < studentResults.size(); i++){
for(unsigned int j = 0; j < studentResults[i].size(); j++){
if(studentResults[i][j] != -1){
competingStudents.push_back(i);
break;
}
}
}kb ennyi. a versenyző diákok számából meg a névre már lehet következtetni, ha tárolod őket.
valahol meg el kell kezdeni, programozáshoz elején idő és kitartás kell, de megéri.
-
scream
veterán
válasz
proci985 #1900 üzenetére
Nem értem,mi az hogy érdemes a valós kódot leírni?
Belinkeltem az egész kódomat még a mostani legelső hszemben, (egy link ami a pastebin.com-ra mutat) majd csak megemlítettem egy kódrészletnél hogy az adott hibát hogyan próbáltam megoldani.
Most hogy már megvan a bekérés meg nagyjából maga a kiválogatás, nem kezdenék bele egy teljesen új programkódba, hanem a meglévőt korrigálnám, hogy a csak -1-el rendelkező tanulókat ne listázza ki...
@dabadab :
Használtam én csak nagyon nem tetszett neki a tanulok i-edik eleme...
Új hozzászólás Aktív témák
● ha kódot szúrsz be, használd a PROGRAMKÓD formázási funkciót!
- Casco és kötelező gépjármű felelősségbiztosítás
- Counter-Strike: Global Offensive (CS:GO) / Counter-Strike 2 (CS2)
- Itt az igazság a Samsung állítólagos Android Auto alternatívájáról
- Újra instabilitásba futott a Raptor Lake generáció
- A fociról könnyedén, egy baráti társaságban
- N€T0X|N: SSD cserék
- Anime filmek és sorozatok
- Iszonyatos mennyiségű hulladékkal járhat a Windows 10 terméktámogatásának vége
- Asztalos klub
- Kínai és egyéb olcsó órák topikja
- További aktív témák...
- Bomba ár! Fujitsu LifeBook U758 - i5-8GEN I 8GB I 256GB SSD I HDMI I 15,6" FHD I W11 I Garancia!
- Csere-Beszámítás! Asztali számítógép PC Játékra. I5 12400F / RTX 3070 / 32GB DDR4 / 1TB SSD
- Új FULL HD webkamera + Számla
- Apple iPad Air 4 64GB Kártyafüggetlen 1Év Garanciával
- Cisco Catalyst C1000-48T-4G-L 48xRJ45 4xSFP switch, CISCO refurbished
Állásajánlatok
Cég: Promenade Publishing House Kft.
Város: Budapest
Cég: PCMENTOR SZERVIZ KFT.
Város: Budapest