• No results found

Föreläsning 5. Träd Binära träd Binärt sökträd som ADT Implementering av binärt sökträd Travestera binärt sökträd Sökning Insättning/borttagning

N/A
N/A
Protected

Academic year: 2022

Share "Föreläsning 5. Träd Binära träd Binärt sökträd som ADT Implementering av binärt sökträd Travestera binärt sökträd Sökning Insättning/borttagning"

Copied!
23
0
0

Loading.... (view fulltext now)

Full text

(1)

Föreläsning 5

 Träd

 Binära träd

 Binärt sökträd som ADT

 Implementering av binärt sökträd

 Travestera binärt sökträd

 Sökning

 Insättning/borttagning

(2)

Terminologi - träd

 Ett träd i datalogi består av en rotnod och ett ändligt antal underträd

(subtrees)

Trädets höjd är antalet nivåer (4 i exemplet).

 Ett träd är en graf där man kan ta sig mellan två noder på endast ett sätt. N noder ger N-1 bågar.

 Vi kommer främst titta på binära träd.

nivå 0 nivå 1 nivå 2 nivå 3

(3)

Binära träd

 Ett binärt träd är ett träd där varje nod har maximalt 2 barn

 Definition:

Ett binärt träd är antingen tomt eller så har

rotnoden 2 underträd (subtree) som också är

binära träd (vänster och höger underträd).

(4)

Binärt sökträd (BST)

 Ett binärt sökträd är ett binärt träd som är ordnat efter nodernas nycklar

 För godtycklig nod gäller

alla nycklar i nodens vänstra underträdet är mindre än nodens nyckel

alla nycklar i nodens högra underträdet är större än nodens nyckel

vänster och höger underträd är också binära sökträd

varje nod är unik (inga kopior)

(5)

Traversera

 Att besöka alla noder i ett träd kallas att traversera trädet.

 Tre traverseringsordningar:

Inorder. Besök först trädets vänstra del, sedan noden själv och sist trädets högra del. (1,2,3,4,5,6,7)

Preorder. Besök först noden själv, sedan trädets vänstra del och sist trädets högra del. (4,2,1,3,6,5,7)

Postorder. Besök först trädets vänstra del, sedan trädets högra del och sist noden själv. (1,3,2,5,7,6,4)

Normalt använder vi inorder.

(6)

Binärt sökträd som ADT

 Är skapat för att lätt kunna söka och lägga till och ta ut (log n). För att det ska fungera måste trädet vara bra balanserat.

 Operationer: searchTree(nyckel)

insertTree(element)

deleteTree(nyckel)

(7)

binarySearchTree.h

typedef struct{

char key[WORDLENGTH];

} Data;

typedef struct treeNode TreeNode;

struct treeNode{

Data element;

TreeNode *left, *right;

};

typedef struct{

TreeNode *root;

}BinaryTree;

BinaryTree *initBinaryTree();

void insertTree(BinaryTree *bp,Data e);

void inOrder(BinaryTree *bp);

Data *searchTree(BinaryTree *bp,char key[]);

(8)

binarySearchTree.c - initiera

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

#include <string.h>

#include "binarySearchTree.h"

BinaryTree *initBinaryTree()

{ BinaryTree *bp = (BinaryTree*)malloc(sizeof(BinaryTree));

bp->root = NULL;

return bp;

} …

(9)

binarySearchTree.c - traversera

void inOrder(BinaryTree *bp) { inOrderNode(bp->root);

}

void inOrderNode(TreeNode *np) { if(np!=NULL)

{

inOrderNode(np->left);

printf("%s,",(np->element).key);

inOrderNode(np->right);

} }

Det här extrasteget hade vi sluppit om vi inte använt en speciell datastruktur för att representera ett träd utan helt enkelt använt en pekare av typen

TreeNode och kallat den root. Det steget kommer nu behövas på alla funktioner vi väljer att lösa rekursivt.

(10)

binarySearchTree.c – sätta in

void insertTree(BinaryTree *bp,Data e) {

TreeNode *newNode = (TreeNode*)malloc(sizeof(TreeNode));

newNode->element = e;

newNode->left=newNode->right=NULL;

if(bp->root==NULL)

bp->root=newNode;

else

insertNodeInTree(bp->root,newNode);

}

(11)

binarySearchTree.c sätta in

void insertNodeInTree(TreeNode *tree,TreeNode *newNode)

{ int komp=strcmp((tree->element).key,(newNode->element).key);

assert(komp!=0);

if(komp<0) {

if(tree->right==NULL)

tree->right=newNode;

else

insertNodeInTree(tree->right,newNode);

} else {

if(tree->left==NULL)

tree->left=newNode;

else

insertNodeInTree(tree->left,newNode);

} }

(12)

binarySearchTree.c - söka

Data *searchTree(BinaryTree *bp,char key[]) { if(bp->root==NULL)

return NULL;

else {

TreeNode *found = searchTreeNode(bp->root, key);

if(found!=NULL)

return &(found->element);

else

return NULL;

} }

(13)

binarySearchTree.c - söka

TreeNode *searchTreeNode(TreeNode *tree, char key[]) { int komp=strcmp((tree->element).key,key);

if(komp==0) return tree;

else if(komp<0){

if(tree->right==NULL) return NULL;

else

return searchTreeNode(tree->right,key);

}else{

if(tree->left==NULL) return NULL;

else

return searchTreeNode(tree->left,key);

} }

(14)

Ta bort från binärt sökträd

Det finns tre fall att ta hänsyn till när vi tar bort en nod:

 noden är ett löv

 noden har bara ett subträd

 noden har både vänster och höger subträd

Fall 1 är trivialt: vi sätter helt enkelt förälderns

relevanta subträd till NULL

(15)

Noden har bara ett subträd

 Också relativt enkelt. Vi ersätter helt enkelt noden med dess barn.

 Ex: Vi ska ta bort 4:

8 4

6

9

7 5

8

6

9

7 5

(16)

Noden har både vänster och höger subträd

Vi måste nu lösa vad vi ska göra med de två barnen. Lösningen är att vi ersätter noden med den minsta noden i det högra underträdet. Denna kan inte ha något vänsterbarn (den är ju minst) och därmed lätta att ta bort (fall 2)

Ex: vi vill ta bort nod B.

H B

E

N

F C

A

D

H C

E

N

F A

D

(17)

deleteNode

För att implementera deleteTree kommer vi att skapa en intern hjälpfunktion som tar som parameter en pekare till noden som ska tas bort och returnerar en pekare till rotnoden till det nya subträdet. I exemplet nedan skickar man in en pekare till B och funktionen returnerar en pekare till C med underträdet i den högra bilden:

H B

E

N

F C

A

D

H C

E

N

F A

D

(18)

deleteNode - hjälpfunktion

TreeNode *deleteNode(TreeNode *np){

TreeNode *newSubTree;

if(np==NULL) return NULL;

else if(np->right==NULL){

newSubTree=np->left;

free(np);

return newSubTree;

}else if(np->left==NULL){

newSubTree=np->right;

free(np);

return newSubTree;

}else{

H

B N

A

H B

E

N

(19)

hjälpfunktion forts.

TreeNode *parentToMin;

TreeNode *minOfRightTree;

minOfRightTree = np->right;

if(minOfRightTree->left==NULL){

minOfRightTree->left=np->left;

free(np);

return minOfRightTree;

}

while(minOfRightTree->left!=NULL){

parentToMin = minOfRightTree;

minOfRightTree = minOfRightTree->left;

}

parentToMin->left = minOfRightTree->right;

minOfRightTree->left=np->left;

minOfRightTree->right=np->right;

free(np);

return minOfRightTree;

} }

H B

E

N

F A

H B

E

N

F C

A

D

parent min

(20)

deleteNode -gränssnittsfunktion

Data deleteTree(BinaryTree *bp,char key[]){

Data d;

bp->root=deleteNodeTree(bp->root,key,&d);

return d;

}

Observera hur deletNodeTree ska returnera en pekare till hela det nya trädet!

Den kommer sedan rekursivt leta sig ner i trädet mot rätt nod och hela tiden returnera en pekare till trädet där den är tills den hittar rätt nod. Då skickar den denna till vår hjälpfunktion som returnerar en pekare till det nya trädet.

(21)

deleteNode –söker upp rätt nod

TreeNode *deleteNodeTree(TreeNode *tree,char key[],Data *d){

int komp=strcmp((tree->element).key,key);

if(komp==0){

*d = tree->element;

return deleteNode(tree);

}else if(komp<0){

if(tree->right==NULL) return tree;//fanns ej else{

tree->right = deleteNodeTree(tree->right,key,d);

return tree;

} }else{

if(tree->left==NULL)

return tree;//fanns ej else{

tree->left = deleteNodeTree(tree->left,key,d);

return tree;

}}}

(22)

Inlämningsuppgifter

 Följande uppgifter redovisas senast måndag den 6 februari och kan inte redovisas senare:

5.5, 5.A, 5.B, 5.C/5.7, 5.D, 5.E

 Dessa uppgifter bör göras nu för att ni ska kunna

följa kursen på ett bra sätt. Övriga kan ni göra

vid tillfälle för högre betyg.

(23)

Uppgifter ej i boken

Utgå från föreläsningens implementering av ett binärt sökträd när du löser nedanstående uppgifter

5.A

Skriv en main som läser in sju ord från användaren och placerar dessa i ett BST. Kör programmet och skriv in 7 ord så att trädet får minsta möjliga höjd. Kör programmet och skriv in 7 ord så att trädet får maximal höjd.

(2p)

5.B

Skriv funktioner som traverserar trädet med preOrder och inOrder.

(1p)

5.C

Skriv två funktioner numberOfLeaves och numberOfNodes till vår implementation från föreläsningen.

(2p)

5.D

Skriv om sökfunktionen så att den är iterativ istället för rekursiv.

(3p)

5.E

Skriv en funktion maximum som returnerar det största värdet i ett binärt sökträd. Skriv en rekursiv och en iterativ version.

(2p)

References

Related documents

En stor andel av de träd som innehåller eller har goda förutsättningar att inne- hålla höga biologiska värden återfinns idag längs med eller i anslutning till våra

De har en större andel friska träd, större andel skyddsvärda träd, större andel träd med stora hål och större andel efterträdare än det finns i skogen. Samtidigt

Att det här var ett speciellt träd var inte något som de vuxna med ord talade om för barnen, Lars säger: ”Egentligen inte, det var så fullkomligt självklart att det här var

Yrkesfolk använder en tillväxtborr för att titta hur gammalt ett träd är och hur fort det har växt.. Eventuellt kan läraren få låna en tillväxtborr från Skogsstyrelsen

Material: Två tavelramar av vykortsstorlek (t.ex. från IKEA), insektsnät att spänna över den ena ramen, häft- pistol för att fästa nätet, dagstidningar, mixer eller elvisp,

Under en utomhusövning hjälps barn och vuxna åt med att räkna träd: riktigt små träd (barn), mellanstora träd (tonåringar), stora träd (föräldrar) och

Däremot ger varje period av regn eller torka upphov till mer eller mindre tydliga ringar?. Titta

Myotis grisescens Pipistrellus macrotis Kerivoula myrella. Sciurus spadiceus