NoNameCracksInc

c402

Oct 21st, 2017
435
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.43 KB | None | 0 0
  1.  
  2. /* c402.c: ********************************************************************}
  3. {* Téma: Nerekurzivní implementace operací nad BVS
  4. ** Implementace: Petr Přikryl, prosinec 1994
  5. ** Úpravy: Petr Přikryl, listopad 1997
  6. ** Petr Přikryl, květen 1998
  7. ** Převod do jazyka C: Martin Tuček, srpen 2005
  8. ** Úpravy: Bohuslav Křena, listopad 2009
  9. **
  10. ** S využitím dynamického přidělování paměti, implementujte NEREKURZIVNĚ
  11. ** následující operace nad binárním vyhledávacím stromem (předpona BT znamená
  12. ** Binary Tree a je u identifikátorů uvedena kvůli možné kolizi s ostatními
  13. ** příklady):
  14. **
  15. ** BTInit .......... inicializace stromu
  16. ** BTInsert ........ nerekurzivní vložení nového uzlu do stromu
  17. ** BTPreorder ...... nerekurzivní průchod typu pre-order
  18. ** BTInorder ....... nerekurzivní průchod typu in-order
  19. ** BTPostorder ..... nerekurzivní průchod typu post-order
  20. ** BTDisposeTree ... zruš všechny uzly stromu
  21. **
  22. ** U všech funkcí, které využívají některý z průchodů stromem, implementujte
  23. ** pomocnou funkci pro nalezení nejlevějšího uzlu v podstromu.
  24. **
  25. ** Přesné definice typů naleznete v souboru c402.h. Uzel stromu je typu tBTNode,
  26. ** ukazatel na něj je typu tBTNodePtr. Jeden uzel obsahuje položku int Cont,
  27. ** která současně slouží jako užitečný obsah i jako vyhledávací klíč
  28. ** a ukazatele na levý a pravý podstrom (LPtr a RPtr).
  29. **
  30. ** Příklad slouží zejména k procvičení nerekurzivních zápisů algoritmů
  31. ** nad stromy. Než začnete tento příklad řešit, prostudujte si důkladně
  32. ** principy převodu rekurzivních algoritmů na nerekurzivní. Programování
  33. ** je především inženýrská disciplína, kde opětné objevování Ameriky nemá
  34. ** místo. Pokud se Vám zdá, že by něco šlo zapsat optimálněji, promyslete
  35. ** si všechny detaily Vašeho řešení. Povšimněte si typického umístění akcí
  36. ** pro různé typy průchodů. Zamyslete se nad modifikací řešených algoritmů
  37. ** například pro výpočet počtu uzlů stromu, počtu listů stromu, výšky stromu
  38. ** nebo pro vytvoření zrcadlového obrazu stromu (pouze popřehazování ukazatelů
  39. ** bez vytváření nových uzlů a rušení starých).
  40. **
  41. ** Při průchodech stromem použijte ke zpracování uzlu funkci BTWorkOut().
  42. ** Pro zjednodušení práce máte předem připraveny zásobníky pro hodnoty typu
  43. ** bool a tBTNodePtr. Pomocnou funkci BTWorkOut ani funkce pro práci
  44. ** s pomocnými zásobníky neupravujte
  45. **
  46. ** Pozor! Je třeba správně rozlišovat, kdy použít dereferenční operátor *
  47. ** (typicky při modifikaci) a kdy budeme pracovat pouze se samotným ukazatelem
  48. ** (např. při vyhledávání). V tomto příkladu vám napoví prototypy funkcí.
  49. ** Pokud pracujeme s ukazatelem na ukazatel, použijeme dereferenci.
  50. **/
  51.  
  52. #include "c402.h"
  53. int solved;
  54.  
  55. void BTWorkOut (tBTNodePtr Ptr) {
  56. /* ---------
  57. ** Pomocná funkce, kterou budete volat při průchodech stromem pro zpracování
  58. ** uzlu určeného ukazatelem Ptr. Tuto funkci neupravujte.
  59. **/
  60.  
  61. if (Ptr==NULL)
  62. printf("Chyba: Funkce BTWorkOut byla volána s NULL argumentem!\n");
  63. else
  64. printf("Výpis hodnoty daného uzlu> %d\n",Ptr->Cont);
  65. }
  66.  
  67. /* -------------------------------------------------------------------------- */
  68. /*
  69. ** Funkce pro zásobník hotnot typu tBTNodePtr. Tyto funkce neupravujte.
  70. **/
  71.  
  72. void SInitP (tStackP *S)
  73. /* ------
  74. ** Inicializace zásobníku.
  75. **/
  76. {
  77. S->top = 0;
  78. }
  79.  
  80. void SPushP (tStackP *S, tBTNodePtr ptr)
  81. /* ------
  82. ** Vloží hodnotu na vrchol zásobníku.
  83. **/
  84. {
  85. /* Při implementaci v poli může dojít k přetečení zásobníku. */
  86. if (S->top==MAXSTACK)
  87. printf("Chyba: Došlo k přetečení zásobníku s ukazateli!\n");
  88. else {
  89. S->top++;
  90. S->a[S->top]=ptr;
  91. }
  92. }
  93.  
  94. tBTNodePtr STopPopP (tStackP *S)
  95. /* --------
  96. ** Odstraní prvek z vrcholu zásobníku a současně vrátí jeho hodnotu.
  97. **/
  98. {
  99. /* Operace nad prázdným zásobníkem způsobí chybu. */
  100. if (S->top==0) {
  101. printf("Chyba: Došlo k podtečení zásobníku s ukazateli!\n");
  102. return(NULL);
  103. }
  104. else {
  105. return (S->a[S->top--]);
  106. }
  107. }
  108.  
  109. bool SEmptyP (tStackP *S)
  110. /* -------
  111. ** Je-li zásobník prázdný, vrátí hodnotu true.
  112. **/
  113. {
  114. return(S->top==0);
  115. }
  116.  
  117. /* -------------------------------------------------------------------------- */
  118. /*
  119. ** Funkce pro zásobník hotnot typu bool. Tyto funkce neupravujte.
  120. */
  121.  
  122. void SInitB (tStackB *S) {
  123. /* ------
  124. ** Inicializace zásobníku.
  125. **/
  126.  
  127. S->top = 0;
  128. }
  129.  
  130. void SPushB (tStackB *S,bool val) {
  131. /* ------
  132. ** Vloží hodnotu na vrchol zásobníku.
  133. **/
  134. /* Při implementaci v poli může dojít k přetečení zásobníku. */
  135. if (S->top==MAXSTACK)
  136. printf("Chyba: Došlo k přetečení zásobníku pro boolean!\n");
  137. else {
  138. S->top++;
  139. S->a[S->top]=val;
  140. }
  141. }
  142.  
  143. bool STopPopB (tStackB *S) {
  144. /* --------
  145. ** Odstraní prvek z vrcholu zásobníku a současně vrátí jeho hodnotu.
  146. **/
  147. /* Operace nad prázdným zásobníkem způsobí chybu. */
  148. if (S->top==0) {
  149. printf("Chyba: Došlo k podtečení zásobníku pro boolean!\n");
  150. return(NULL);
  151. }
  152. else {
  153. return(S->a[S->top--]);
  154. }
  155. }
  156.  
  157. bool SEmptyB (tStackB *S) {
  158. /* -------
  159. ** Je-li zásobník prázdný, vrátí hodnotu true.
  160. **/
  161. return(S->top==0);
  162. }
  163.  
  164. /* -------------------------------------------------------------------------- */
  165. /*
  166. ** Následuje jádro domácí úlohy - funkce, které máte implementovat.
  167. */
  168.  
  169. void BTInit (tBTNodePtr *RootPtr) {
  170. /* ------
  171. ** Provede inicializaci binárního vyhledávacího stromu.
  172. **
  173. ** Inicializaci smí programátor volat pouze před prvním použitím binárního
  174. ** stromu, protože neuvolňuje uzly neprázdného stromu (a ani to dělat nemůže,
  175. ** protože před inicializací jsou hodnoty nedefinované, tedy libovolné).
  176. ** Ke zrušení binárního stromu slouží procedura BTDisposeTree.
  177. **
  178. ** Všimněte si, že zde se poprvé v hlavičce objevuje typ ukazatel na ukazatel,
  179. ** proto je třeba při práci s RootPtr použít dereferenční operátor *.
  180. **/
  181.  
  182.  
  183. //nastavim prvni prvek na NULL
  184.  
  185. (*RootPtr)=NULL;
  186. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  187. }
  188.  
  189. void BTInsert (tBTNodePtr *RootPtr, int Content) {
  190. /* --------
  191. ** Vloží do stromu nový uzel s hodnotou Content.
  192. **
  193. ** Z pohledu vkládání chápejte vytvářený strom jako binární vyhledávací strom,
  194. ** kde uzly s hodnotou menší než má otec leží v levém podstromu a uzly větší
  195. ** leží vpravo. Pokud vkládaný uzel již existuje, neprovádí se nic (daná hodnota
  196. ** se ve stromu může vyskytnout nejvýše jednou). Pokud se vytváří nový uzel,
  197. ** vzniká vždy jako list stromu. Funkci implementujte nerekurzivně.
  198. **/
  199.  
  200. //vytvorim si novy list
  201. tBTNodePtr item=NULL,item_2=NULL;
  202. item_2=malloc(sizeof(tBTNodePtr)*sizeof(tBTNodePtr)*sizeof(tBTNodePtr)*sizeof(int));
  203. item_2->Cont=Content;
  204. item_2->LPtr=NULL;
  205. item_2->RPtr=NULL;
  206.  
  207. //pokud jsme na zacatku okamzite ho ulozim
  208. if ((*RootPtr)==NULL)
  209. (*RootPtr)=item_2;
  210.  
  211. //jinak projdu cely strom a ulozim ho na konec
  212. else
  213. {
  214. //pomocna pro pruchod stromu
  215. item=(*RootPtr);
  216.  
  217. //dokud jsme nenrazili na konec stromu
  218. while (item!=NULL)
  219. {
  220.  
  221. //pokud se tam jiz tato hodnota nachazi, uvolnim novy list a koncim funkci
  222. if (item->Cont == Content)
  223. {
  224. free(item_2);
  225. return ;
  226. }
  227.  
  228. //pokud je hodnota vetsi nez hledany prvek jdu do leva
  229. else if (item->Cont > Content)
  230. {
  231.  
  232. //pokud se v levo nic nenachazi, ulozim tam nove vytvoreny list a koncim funkci
  233. if (item->LPtr==NULL)
  234. {
  235. item->LPtr=item_2;
  236. return;
  237. }
  238. //pokud, ale v levo neco je, nactu levy uzel a pokracuji v cyklu
  239. item=item->LPtr;
  240. }
  241. //pokud je hodnota mensi nez hledany prvek jdu do prava
  242. else if (item->Cont < Content)
  243. {
  244.  
  245. //pokud se v pravo nic nenachazi, ulozim tam nove vytvoreny list a koncim funkci
  246. if (item->RPtr==NULL)
  247. {
  248. item->RPtr=item_2;
  249. return;
  250. }
  251.  
  252. //pokud, ale v pravo neco je, nactu pravy uzel a pokracuji v cyklu
  253. item=item->RPtr;
  254. }
  255. }
  256. }
  257.  
  258. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  259. }
  260.  
  261. /* PREORDER */
  262.  
  263. void Leftmost_Preorder (tBTNodePtr ptr, tStackP *Stack) {
  264. /* -----------------
  265. ** Jde po levě větvi podstromu, dokud nenarazí na jeho nejlevější uzel.
  266. **
  267. ** Při průchodu Preorder navštívené uzly zpracujeme voláním funkce BTWorkOut()
  268. ** a ukazatele na ně is uložíme do zásobníku.
  269. **/
  270.  
  271. //s pouzitim zasobniku prochazim strom
  272. tBTNodePtr item;
  273. item=ptr;
  274.  
  275. //dokud nejsme na konci
  276. while (item!=NULL)
  277. {
  278. //tisknu uzel, na kterem se nachazim
  279. BTWorkOut(item);
  280.  
  281. //ulozim uzel pro pozdejsi pruchod do prava na zasobnik
  282. SPushP(Stack,item);
  283.  
  284. //a jdu do leva
  285. item=item->LPtr;
  286. }
  287.  
  288.  
  289. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  290. }
  291.  
  292. void BTPreorder (tBTNodePtr RootPtr) {
  293. /* ----------
  294. ** Průchod stromem typu preorder implementovaný nerekurzivně s využitím funkce
  295. ** Leftmost_Preorder a zásobníku ukazatelů. Zpracování jednoho uzlu stromu
  296. ** realizujte jako volání funkce BTWorkOut().
  297. **/
  298.  
  299. //pokud ve strome vubec neco je
  300. if (RootPtr!=NULL)
  301. {
  302.  
  303. //inicializace zasobniku, pomocneho stromu a prvni pruchod do leva
  304. //mam radsi dynamicke zasobniky
  305. tStackP *Stack=NULL;
  306. Stack=malloc (sizeof (tStackP));
  307. tBTNodePtr item=RootPtr;
  308. SInitP(Stack);
  309. Leftmost_Preorder(item,Stack);
  310.  
  311. //dokud enni zasobnik prazdny
  312. while (!SEmptyP(Stack))
  313. {
  314.  
  315. //do promenne ulozim ukazatel na uzel
  316. item=STopPopP(Stack);
  317.  
  318. //a projfu uzel tentokrat do prava
  319. Leftmost_Preorder(item->RPtr,Stack);
  320. }
  321. free (Stack);
  322. }
  323. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  324. }
  325.  
  326.  
  327. /* INORDER */
  328.  
  329. void Leftmost_Inorder(tBTNodePtr ptr, tStackP *Stack) {
  330. /* ----------------
  331. ** Jde po levě větvi podstromu, dokud nenarazí na jeho nejlevější uzel.
  332. **
  333. ** Při průchodu Inorder ukládáme ukazatele na všechny navštívené uzly do
  334. ** zásobníku.
  335. **/
  336. //s pouzitim zasobniku prochazim strom
  337. tBTNodePtr item;
  338. item=ptr;
  339.  
  340. //dokud nejsme na konci
  341. while (item!=NULL)
  342. {
  343. //dam stavajici uzel na zasobnik pro pozdejsi pruchod do prava
  344. SPushP(Stack,item);
  345.  
  346. //a jdu do leva
  347. item=item->LPtr;
  348. }
  349.  
  350.  
  351.  
  352. // solved = FALSE; /* V případě řešení smažte tento řádek! */
  353.  
  354. }
  355.  
  356. void BTInorder (tBTNodePtr RootPtr) {
  357. /* ---------
  358. ** Průchod stromem typu inorder implementovaný nerekurzivně s využitím funkce
  359. ** Leftmost_Inorder a zásobníku ukazatelů. Zpracování jednoho uzlu stromu
  360. ** realizujte jako volání funkce BTWorkOut().
  361. **/
  362.  
  363. //pokud vubec neco je ve strome
  364. if (RootPtr!=NULL)
  365. {
  366.  
  367. //pocatecni inicializace a vytvoreni zasobniku
  368. //mam radsi dynamicke zasobniky
  369. tStackP *Stack=NULL;
  370. Stack=malloc (sizeof (tStackP));
  371. tBTNodePtr item=RootPtr;
  372. SInitP(Stack);
  373.  
  374. //prvni pruchod do leva
  375. Leftmost_Inorder(item,Stack);
  376. while (!SEmptyP(Stack))
  377. {
  378.  
  379. //vytahnu si ze zasobniku prvni uzel
  380. item=STopPopP(Stack);
  381. //vytisknu ho
  382. BTWorkOut(item);
  383.  
  384. //a prochazim jeho pravy list do leva
  385. Leftmost_Inorder(item->RPtr,Stack);
  386. }
  387. free (Stack);
  388. }
  389.  
  390. // solved = FALSE; /* V případě řešení smažte tento řádek! */
  391. }
  392.  
  393. /* POSTORDER */
  394.  
  395. void Leftmost_Postorder (tBTNodePtr ptr, tStackP *StackP, tStackB *StackB) {
  396. /* --------
  397. ** Jde po levě větvi podstromu, dokud nenarazí na jeho nejlevější uzel.
  398. **
  399. ** Při průchodu Postorder ukládáme ukazatele na navštívené uzly do zásobníku
  400. ** a současně do zásobníku bool hodnot ukládáme informaci, zda byl uzel
  401. ** navštíven poprvé a že se tedy ještě nemá zpracovávat.
  402. **/
  403.  
  404. //s pouzitim dvou zasobniku prochazim strom
  405. tBTNodePtr item;
  406. item=ptr;
  407.  
  408. //dkud nejsme na konci stromu
  409. while (item!=NULL)
  410. {
  411.  
  412. //na zasobnik ulozim stavajici uzel
  413. SPushP(StackP,item);
  414.  
  415. //a ulozim ze jsem sel do leva
  416. SPushB(StackB,true);
  417. item=item->LPtr;
  418. }
  419.  
  420.  
  421. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  422. }
  423.  
  424. void BTPostorder (tBTNodePtr RootPtr) {
  425. /* -----------
  426. ** Průchod stromem typu postorder implementovaný nerekurzivně s využitím funkce
  427. ** Leftmost_Postorder, zásobníku ukazatelů a zásobníku hotdnot typu bool.
  428. ** Zpracování jednoho uzlu stromu realizujte jako volání funkce BTWorkOut().
  429. **/
  430. if (RootPtr!=NULL)
  431. {
  432.  
  433. //ininicializace promennych a zasobniku
  434. bool left;
  435.  
  436. //mam radsi dynamicke zasobniky
  437. tStackP *StackP=NULL;
  438. StackP=malloc (sizeof (tStackP));
  439. tStackB *StackB=NULL;
  440. StackB=malloc (sizeof (tStackB));
  441. tBTNodePtr item;
  442. item = RootPtr;
  443. SInitP(StackP);
  444. SInitB(StackB);
  445.  
  446. //prvni pruchod do leva
  447. Leftmost_Postorder(item,StackP,StackB);
  448. while (!SEmptyP(StackP))
  449. {
  450. //vytahnu si prvni uzel ze saboniku
  451. item=STopPopP(StackP);
  452. //ale on tam musi zustat
  453. SPushP(StackP,item);
  454.  
  455. //zjistim, jestli jsem posledne sel do leva
  456. left=STopPopB(StackB);
  457.  
  458. //pokud ano
  459. if (left)
  460. {
  461. //pujdu do prava
  462. SPushB(StackB,false);
  463. Leftmost_Postorder(item->RPtr,StackP,StackB);
  464. }
  465.  
  466. //pokud jsem sel do prava
  467. else
  468. {
  469. //vytahnu uzel
  470. item=STopPopP(StackP);
  471. //a vytisknu ho
  472. BTWorkOut(item);
  473. }
  474. }
  475. free(StackP);
  476. free(StackB);
  477. }
  478. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  479. }
  480.  
  481.  
  482. void BTDisposeTree (tBTNodePtr *RootPtr) {
  483. /* -------------
  484. ** Zruší všechny uzly stromu a korektně uvolní jimi zabranou paměť.
  485. **
  486. ** Funkci implementujte nerekurzivně s využitím zásobníku ukazatelů.
  487. **/
  488. //pokud ve stromu vubec neco je, tak ho smazu
  489. if ((*RootPtr)!=NULL)
  490. {
  491.  
  492. //mama radsi dynamicke zasobniky
  493. tStackP *StackP=NULL;
  494. StackP=malloc (sizeof (tStackP));
  495. tBTNodePtr item_2;
  496. SInitP(StackP);
  497.  
  498. //cyklus repeat
  499. do
  500. {
  501. //pokud jsme na konci vetve
  502. if ((*RootPtr)==NULL)
  503. {
  504. //a neni prazdny zasobnik, tak si vytahneme uzel a pokracujeme v cyklu
  505. if (!SEmptyP(StackP))
  506. (*RootPtr)=STopPopP(StackP);
  507. }
  508.  
  509. //pokud jsme nekde uprostred vetve
  510. else
  511. {
  512. //pokud ve stavajicim uzlu v pravo neco je, ulozim uzel na zasobnik
  513. if ((*RootPtr)->RPtr!=NULL)
  514. SPushP(StackP,(*RootPtr)->RPtr);
  515.  
  516. //posunu se do leva a prvek, na kterem jsem doposud byl odsranim
  517. item_2=(*RootPtr);
  518. (*RootPtr)=(*RootPtr)->LPtr;
  519. free(item_2);
  520. item_2=NULL;
  521. }
  522. }
  523. while (!((*RootPtr)==NULL && SEmptyP(StackP)));
  524. //cyklus do while, pracuje podobne jako repeat v pascalu, s tim rozdilem ze
  525. //ukoncovaci podminku musime znegovat
  526.  
  527. free(StackP);
  528. }
  529.  
  530. //solved = FALSE; /* V případě řešení smažte tento řádek! */
  531. }
  532.  
  533. /* konec c402.c */
Advertisement
Add Comment
Please, Sign In to add comment