Presentation is loading. Please wait.

Presentation is loading. Please wait.

Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 9: Lists and Trees for Structuring Sounds.

Similar presentations


Presentation on theme: "Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 9: Lists and Trees for Structuring Sounds."— Presentation transcript:

1 Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 9: Lists and Trees for Structuring Sounds

2 Chapter Objectives

3 Story Structuring sounds into songs (? Collections?) Version 1: Representing linearity through elements order. Repeating and weaving with sounds Finding and replacing sounds in a list How do trace and debug what we’re doing with sounds and lists? Structuring sounds into songs Version 2: Creating trees of sounds. Traversing in a tree Pre-order and post-order

4 SoundElement: Creating a linked list of sounds /** * Sounds for a linked list **/ public class SoundElement { /** * The sound this element is associated with **/ Sound mySound; /** * The next element to process **/ public SoundElement next;

5 Constructing an element /** * Constructor sets next to null * and references the input sound. **/ public SoundElement(Sound aSound){ next = null; mySound = aSound; }

6 Linked List blah-blah-blah /** * Methods to set and get next elements * @param nextOne next element in list **/ public void setNext(SoundElement nextOne){ this.next = nextOne; } public SoundElement getNext(){ return this.next; }

7 Printing a SoundElement list /** * Provide a printable representation of me * @return the information string */ public String toString(){ return "SoundElement with sound: " + mySound + " (and next: " + next + ")."; } Think about it: What is “next”? What method gets called to convert next into a string? What method is this?

8 Methods for playing /** * The method to get the sound * @return the sound associated with this node */ public Sound getSound(){return mySound;} /** * Play JUST me, blocked. */ public void playSound(){mySound.blockingPlay();} /** * Play JUST me, blocked. */ public void blockingPlay(){mySound.blockingPlay();}

9 Methods for Playing /** * Play the list of sound elements * after me **/ public void playFromMeOn(){ this.collect().play(); } /** * Collect all the sounds from me on, * recursively. **/ public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} }

10 Starting to explore > Sound s = new Sound("D:/cs1316/mediasources/shh-a-h.wav"); > Sound t = new Sound("D:/cs1316/mediasources/croak-h.wav"); > Sound u = new Sound("D:/cs1316/mediasources/clap-q.wav"); > SoundElement e1 = new SoundElement(s); > SoundElement e2 = new SoundElement(t); > SoundElement e3 = new SoundElement(u); > e1.playFromMeOn(); > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a- h.wav number of samples: 11004 (and next: null).

11 How did that happen? How were we able to get that string from typing in e1? By defining the method toString() on a class, we can define how it should appear. VERY useful in debugging!

12 Growing the list > e1.setNext(e2) > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a- h.wav number of samples: 11004 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/croak-h.wav number of samples: 8808 (and next: null).). > e2.setNext(e3) > e1 SoundElement with sound: Sound file: D:/cs1316/mediasources/shh-a- h.wav number of samples: 11004 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/croak-h.wav number of samples: 8808 (and next: SoundElement with sound: Sound file: D:/cs1316/mediasources/clap-q.wav number of samples: 4584 (and next: null).).). Where’s all that coming from?!? When we add in next to our toString(), it calls next’s toString()

13 e1.playFromMeOn() e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next: null e2e3 public void playFromMeOn(){ this.collect().play(); }

14 public Sound collect(){ if (this.getNext() == null) {return mySound;} e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this

15 else {return mySound.append(this.getNext().collect());} e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this We “freeze” this call to e1.collect()

16 public Sound collect(){ if (this.getNext() == null) {return mySound;} mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this Where’s e1? What e1? From e2’s view, there is no e1

17 else {return mySound.append(this.getNext().collect());} mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this We “freeze” this call to e2.collect()

18 public Sound collect(){ if (this.getNext() == null) {return mySound;} mySound: clap- q.wav next:null e3 this We return clap-q.wav

19 else {return mySound.append(this.getNext().collect());} mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this Back in e2.collect(), We return croak- h.wav appended with clap-q.wav

20 else {return mySound.append(this.getNext().collect());} e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next:null e2e3 this Back in e2.collect(), We return shh-a- h.wav appended with croak-h.wav appended with clap-q.wav

21 e1.playFromMeOn() e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next: null e2e3 public void playFromMeOn(){ this.collect().play(); } Now we play shh- a-h.wav appended with croak-h.wav appended with clap-q.wav

22 Testing Sound Lists public class SoundListTest { SoundElement root; public SoundElement root(){ return root;} public void setUp(){ FileChooser.setMediaPath("D:/cs1316/MediaSources/"); Sound s = new Sound(FileChooser.getMediaPath( "scratch- h.wav")); root = new SoundElement(s); s = new Sound(FileChooser.getMediaPath( "gonga-2.wav")); SoundElement one = new SoundElement(s); root.repeatNext(one,10); s = new Sound(FileChooser.getMediaPath( "scritch-q.wav")); SoundElement two = new SoundElement(s); root.weave(two,3,3); s = new Sound(FileChooser.getMediaPath( "clap-q.wav")); SoundElement three = new SoundElement(s); root.weave(three,5,2); root.playFromMeOn(); }

23 Repeating /** * Repeat the input phrase for the number of times specified. * It always appends to the current node, NOT insert. * @param nextOne node to be copied in to list * @param count number of times to copy it in. */ public void repeatNext(SoundElement nextOne,int count) { SoundElement current = this; // Start from here SoundElement copy; // Where we keep the current copy for (int i=1; i <= count; i++) { copy = nextOne.copyNode(); // Make a copy current.setNext(copy); // Set as next current = copy; // Now append to copy } Shockingly similar to what we saw before!

24 Copying a node (for repeat and weave) /** * copyNode returns a copy of this element * @return another element with the same sound */ public SoundElement copyNode() { Sound copySound = new Sound(mySound); SoundElement returnMe = new SoundElement(copySound); return returnMe; }

25 Weaving /** * Weave the input sound count times every skipAmount elements * @param nextOne SoundElement to be copied into the list * @param count how many times to copy * @param skipAmount how many nodes to skip per weave */ public void weave(SoundElement nextOne, int count, int skipAmount) { SoundElement current = this; // Start from here SoundElement copy; // Where we keep the one to be weaved in SoundElement oldNext; // Need this to insert properly int skipped; // Number skipped currently for (int i=1; i <= count; i++) { copy = nextOne.copyNode(); // Make a copy //Skip skipAmount nodes skipped = 1; while ((current.getNext() != null) && (skipped < skipAmount)) { current = current.getNext(); skipped++; }; oldNext = current.getNext(); // Save its next current.insertAfter(copy); // Insert the copy after this one current = oldNext; // Continue on with the rest if (current == null) // Did we actually get to the end early? break; // Leave the loop } Again, shockingly similar to what we saw before! Should we break before the last insert (when we get to the end) or after?

26 What? You don’t like gongs? So, what happens when you have umpteen copies of gong, but you don’t like gongs? Yes, we can remake the list, but what if you couldn’t?

27 Degong-ing the SoundListTest public void degong(){ Sound gong = new Sound(FileChooser.getMediaPath( "gonga- 2.wav")); Sound snap = new Sound(FileChooser.getMediaPath( "snap- tenth.wav")); root.replace(gong,snap); }

28 Replacing one sound by another in the list (recursively) /** * Replace the one sound with the other sound * in all the elements from me on. * Decide two sounds are equal if come from same filename * @param oldSound sound to be replaced * @param newSOund sound to put in its place **/ public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} if (next != null) {next.replace(oldSound,newSound);} }

29 Imagine: e1.replace(croak,clap) e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next: null e2e3

30 public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next: null e2e3 this

31 if (next != null) {next.replace(oldSound,newSound);} e1 mySound: shh-a- h.wav next: mySound: croak- h.wav next: mySound: clap- q.wav next: null e2e3 this

32 public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} mySound: croak- h.wav clap- q.wav next: mySound: clap- q.wav next: null e2e3 this This is a match!

33 if (next != null) {next.replace(oldSound,newSound);} mySound: croak- h.wav clap- q.wav next: mySound: clap- q.wav next: null e2e3 this

34 public void replace(Sound oldSound, Sound newSound){ if (mySound.getFileName() != null) {if (mySound.getFileName().equals(oldSound.getFileName())) {mySound = newSound;}} mySound: clap- q.wav next: null e3 this

35 if (next != null) {next.replace(oldSound,newSound);} mySound: clap- q.wav next: null e3 this And we’re done! We do return all the way back up again, but there’s nothing else to be done.

36 Tracing what’s happening Use “Debug Mode” from Debugger menu Type in variable names to trace. Set Breakpoints (Control-B) on the lines you want to stop in. Step over—skips to the next line Step in—skips in to that method call Resume—go to the next breakpoint

37

38 Version 2: When lists aren’t good enough Do we think about music as a linear list of sounds? That is how we experience it. Or do we tend to cluster the sounds? Verse, chorus, verse? This motif, that motif, this motif? And what about this cool idea of embedding operations into the data structure?

39 Creating a tree of sounds SoundBranch ScaleBranchSoundBranch childrennext Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest

40 Creating and playing our tree of sounds Welcome to DrJava. > SoundTreeExample tree = new SoundTreeExample(); > tree.play() > tree.playScaled(2.0); > tree.play();

41 SoundTreeExample public class SoundTreeExample { ScaleBranch scaledBranch; // Needed between methods SoundBranch root; public SoundBranch getRoot() {return root;} /** * Constructor to set up the example */ public SoundTreeExample() { setUp(); }

42 Setting up the basic sounds public void setUp() { Sound clap = new Sound(FileChooser.getMediaPath("clap-q.wav")); Sound chirp = new Sound(FileChooser.getMediaPath("chirp-2.wav")); Sound rest = new Sound(FileChooser.getMediaPath("rest-1.wav")); Sound snap = new Sound(FileChooser.getMediaPath("snap- tenth.wav")); Sound clink = new Sound(FileChooser.getMediaPath("clink- tenth.wav")); Sound clave = new Sound(FileChooser.getMediaPath("clave- twentieth.wav")); Sound gong = new Sound(FileChooser.getMediaPath("gongb-2.wav"));

43 Build the root and first branch root = new SoundBranch(); SoundNode sn; SoundBranch branch1 = new SoundBranch(); sn = new SoundNode(clap.append(rest).append(snap)); branch1.addChild(sn); sn = new SoundNode(rest.append(snap).append(rest)); branch1.addChild(sn);

44 A ScaleBranch and last Branch scaledBranch = new ScaleBranch(1.0); sn = new SoundNode(clink.append(clave).append(gong)); scaledBranch.addChild(sn); sn = new SoundNode(rest.append(chirp).append(clap)); scaledBranch.addChild(sn); SoundBranch branch2 = new SoundBranch(); sn = new SoundNode(clap.append(snap).append(snap)); branch2.addChild(sn); sn = new SoundNode(rest.append(snap).append(clap)); branch2.addChild(sn);

45 Building the whole tree root.addChild(branch1); root.addChild(scaledBranch); root.addChild(branch2); }

46 Playing the tree, and changing the scale public void play(){ root.playFromMeOn(); } public void playScaled(double factor){ scaledBranch.setFactor(factor); root.playFromMeOn(); }

47 Method to test the whole tree /** * Method to test the tree */ public static void main(String[] args) { SoundTreeExample tree = new SoundTreeExample(); tree.getRoot().collect().play(); }

48 What a tree “looks like” (printed, e.g., toString()) > tree SoundTreeExample@92b1a1 > tree.root() SoundBranch (with child: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 28568 and next: SoundNode (with sound: Sound number of samples: 46034 and next: null and next: ScaleBranch (1.0) SoundBranch (with child: SoundNode (with sound: Sound number of samples: 47392 and next: SoundNode (with sound: Sound number of samples: 32126 and next: null and next: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next))) and next: No next) Obviously, this doesn’t help us much, but the root() does

49 Going deeper: How’d we do that? How we build a tree of sounds is very much like a tree of pictures. Set up a general node abstract class that all other nodes inherit from. Create a leaf node that will store our data of interest (sounds). Create a branch node that will store collections of leaves and references to other branches. Create (as we wish) branch nodes with operations that do things to the children of this branch.

50 Our SoundTree Class Structure abstract CollectableNode Knows next Knows How to do basic list operations, and defines abstract sound operations (can collect() its sound(s)) SoundBranch Knows children Knows How add children, and collect all the sounds from its children and next SoundNode Knows mySound Knows How collect itself and its next The subclasses extend CollectableNode

51 Our SoundTree Class Structure (a little further) abstract CollectableNode Knows next Knows How to do basic list operations, and collect() SoundBranch Knows children Knows How add children, and collect() SoundNode Knows mySound Knows How collect() ScaleBranch Knows a scaling factor Knows How to access scaling factor, and to collect from children then scale the resultant sound

52 CollectableNode /** * Stuff that all nodes and branches in the * sound tree know. **/ abstract public class CollectableNode { /** * The next branch/node/whatever to process **/ public CollectableNode next; /** * Constructor for CollectableNode just sets * next to null **/ public CollectableNode(){ next = null; }

53 CollectableNode’s know about linked lists /** * Methods to set and get next elements * @param nextOne next element in list **/ public void setNext(CollectableNode nextOne){ this.next = nextOne; } public CollectableNode getNext(){ return this.next; } The rest of it is there, too: add(), last(), insertAfter(), remove()… But you’ve seen that all before.

54 CollectableNodes know only a little about sound /** * Play the list of sound elements * after me **/ public void playFromMeOn(){ this.collect().play(); } /** * Collect all the sounds from me on **/ abstract public Sound collect(); /** * Collect all the sounds from me on, * but if there's processing, do it after. **/ abstract public Sound collectAfter();

55 SoundNodes know sounds /* * SoundNode is a class representing a drawn picture * node in a scene tree. **/ public class SoundNode extends CollectableNode { /** * The sound I'm associated with **/ Sound mySound; /* * Make me with this sound * @param sound the Sound I'm associated with **/ public SoundNode(Sound sound){ super(); // Call superclass constructor mySound = sound; }

56 What happens if you print a SoundNode /** * Method to return a string with informaiton * about this node */ public String toString() { return "SoundNode (with sound: "+mySound+" and next: "+next; }

57 How SoundNodes collect their sounds /** * Collect all the sounds from me on, * recursively. **/ public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} } “Hang on, how does that work?!?” Wait until we see the rest, then we’ll trace it.

58 SoundBranches know about children public class SoundBranch extends CollectableNode { /* * A list of children to draw */ public CollectableNode children; /* * Construct a branch with children and * next as null **/ public SoundBranch(){ super(); // Call superclass constructor children = null; } Notice: Children could be SoundNodes or other branches— any kind of CollectableNode

59 SoundBranches know about children (contd.) /** * Method to add nodes to children **/ public void addChild(CollectableNode child){ if (children != null) {children.add(child);} else {children = child;} }

60 How SoundBranches print /** * Method to return a string with informaiton * about this branch */ public String toString() { String childString = "No children", nextString="No next"; if (children != null) {childString = children.toString();} if (next != null) {nextString = next.toString();} return "SoundBranch (with child: "+childString+" and next: "+ nextString+")"; }

61 Collecting sounds from SoundBranches /** * Collect all the sound from our children, * then collect from next. * @param pen Turtle to draw with **/ public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect();} else {childSound = new Sound(1);} // Collect from my next if (this.getNext() != null) {childSound=childSound.append(this.getNext().collect());} return childSound; } This collects from the children (or creates a default sound), then from the next’s, and returns them all together

62 ScaleBranches know about scaling (and a factor) public class ScaleBranch extends SoundBranch { /** Amount to scale **/ double factor; /** * Construct a branch with this factor **/ public ScaleBranch(double nufactor){ super(); // Call superclass constructor this.factor = nufactor; } /** Accessors **/ public double getFactor() {return this.factor;} public void setFactor(double nufactor) {this.factor = nufactor;}

63 Scaling the children in a ScaleBranch /** * Collect all the sound from our children, * then collect from next. Scale the children * @param pen Turtle to draw with **/ public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect().scale(factor);} else {childSound = new Sound(1);} // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; }

64 Printing a ScaleBranch /** * Method to return a string with informaiton * about this branch */ public String toString() { return "ScaleBranch ("+factor+") "+super.toString(); }

65 Walking the data structure: At the root > tree.getRoot() SoundBranch (with child: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 28568 and next: SoundNode (with sound: Sound number of samples: 46034 and next: null and next: ScaleBranch (1.0) SoundBranch (with child: SoundNode (with sound: Sound number of samples: 47392 and next: SoundNode (with sound: Sound number of samples: 32126 and next: null and next: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next))) and next: No next)

66 Down the children’s next path > tree.getRoot().children SoundBranch (with child: SoundNode (with sound: Sound number of samples: 28568 and next: SoundNode (with sound: Sound number of samples: 46034 and next: null and next: ScaleBranch (1.0) SoundBranch (with child: SoundNode (with sound: Sound number of samples: 47392 and next: SoundNode (with sound: Sound number of samples: 32126 and next: null and next: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next))) > tree.getRoot().children.getNext() ScaleBranch (1.0) SoundBranch (with child: SoundNode (with sound: Sound number of samples: 47392 and next: SoundNode (with sound: Sound number of samples: 32126 and next: null and next: SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next)) > tree.getRoot().children.getNext().getNext() SoundBranch (with child: SoundNode (with sound: Sound number of samples: 8452 and next: SoundNode (with sound: Sound number of samples: 28568 and next: null and next: No next) > tree.getRoot().children.getNext().getNext().getNext() null

67 Tracing a tree traversal Welcome to DrJava. > SoundTreeExample tree = new SoundTreeExample(); > tree.getRoot().collect().play() This code: (1)Creates a tree object, and fills it up. (2)Then gets the root, collects the sound from the whole tree (traverses the tree), then plays the collected sound. This code: (1)Creates a tree object, and fills it up. (2)Then gets the root, collects the sound from the whole tree (traverses the tree), then plays the collected sound.

68 Tracing the traversal: tree.getRoot().collect().play SoundBranch ScaleBranchSoundBranch childrennext Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest Tree.getRoot()

69 public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect();} else {childSound = new Sound(1);} SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Yes, the root has children, so we ask the first of our children to collect()

70 public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect();} else {childSound = new Sound(1);} SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Yes, we’re in the same method, but now with a new this. It’s really a new call. The call to getRoot().collect() is now paused…

71 public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Now, we’re in SoundNode’s collect() The call to getRoot().children.collect() is now paused… We have a next, so we collect from there, too.

72 public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this We’re in SoundNode’s collect(), with a new SoundNode The call to getRoot().children.children.collect( ) is now paused… We have no next here, so we return “Rest,snap, rest”

73 public Sound collect(){ if (this.getNext() == null) {return mySound;} else {return mySound.append(this.getNext().collect());} } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this We’re back in SoundNode’s collect() We now return “Clap, rest, snap” appended with “Rest, snap, rest”

74 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this We’re now in the second half of SoundBranch’s collect() We have a next, so we move on to call collect() on that.

75 public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect().scale(factor);} else {childSound = new Sound(1);} SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Now we’re in ScaleBranch’s collect() Let’s skip the path down the children. childSound will become “Clink,clave,gong,rest,chirp,clap” scaled by the factor

76 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Second half of ScaleBranch— we get the sounds from next

77 public Sound collect(){ Sound childSound; if (children != null) {childSound = children.collect();} else {childSound = new Sound(1);} SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this We’re in the first half of SoundBranch childSound will become “Clap, snap, snap, rest, snap, clap”

78 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this We’re in the second half of SoundBranch There is no next so we return “Clap, snap, snap, rest, snap, clap”

79 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Back to second half of ScaleBranch getNext().collect() returned “Clap, snap, snap, rest, snap, clap” This returns “Clink,clave,gong,rest,chirp,clap” scaled by the factor, plus “Clap, snap, snap, rest, snap, clap”

80 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this Back in the second half of SoundBranch’s collect() This returns “Clap,rest,snap,rest,snap,rest”, plus “Clink,clave,gong,rest,chirp,clap” scaled by the factor, plus “Clap, snap, snap, rest, snap, clap”

81 // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound);} return childSound; } SoundBranch ScaleBranchSoundBranch Clap,snap,snap Rest, snap, clap Clink,clave, gong Rest, chirp, clap Clap, rest, snap Rest, snap, rest this FINAL RETURN: “Clap,rest,snap,rest,snap,rest”, plus “Clink,clave,gong,rest,chirp,clap” scaled by the factor, plus “Clap, snap, snap, rest, snap, clap” Now we’re back to the second half of this. There is no next

82 That was one kind of tree traversal There are other ways of thinking about traversing a tree! Go down the next before going to the children? Maybe do the scaling to the next instead of to the children? Processing first is called pre-order traversal. Processing last (doing the next) is called post- order traversal.

83 SoundBranch’s collectAfter() /** * Collect all the sound from our children, * then collect from next. * If there's processing, do to Next, not to Children * @param pen Turtle to draw with **/ public Sound collectAfter(){ Sound childSound; if (children != null) {childSound = children.collectAfter();} else {childSound = new Sound(1);} // Collect from my next if (this.getNext() != null) {childSound=childSound.append(this.getNext().collectAfter());} return childSound; }

84 ScaleBranch’s collectAfter() /** * Collect all the sound from our children, * then collect from next. * Scale the next list, not the children * @param pen Turtle to draw with **/ public Sound collectAfter(){ Sound childSound; if (children != null) {childSound = children.collect();} else {childSound = new Sound(1);} // Collect from my next if (this.getNext() != null) {Sound nextSound=this.getNext().collect(); childSound = childSound.append(nextSound.scale(factor));} return childSound; } Notice that we’re scaling what getNext().collect() returns, not what children.collect() returns

85 Trying this in SoundTreeList public void playAfter(){ root.collectAfter().play(); } > tree.playAfter()

86 Where else could we go with this? How about a kind of SoundBranch that knows how to repeat its children a certain number of time? How about a kind of SoundBranch that can mix its children with the next, with a certain percentage of each? Back with pictures: How about a kind of branch that can rotate its children? Or scale them, so you could zoom in or out, or grow/shrink the monster, across frames?

87 Arrays, and Lists, and Trees, oh my! Where we’re going next: We’ve explored lists and trees in a good deal of depth now! You obviously saw lots of similarities between these implementations. “Couldn’t we do this once, instead of duplicating all this code?!?” YES! Let us show you… “Man, what I really want to do is user interfaces with Java—real applications! What does this all have to do with that?!?” A user interface is a tree. Let us show you…


Download ppt "Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 9: Lists and Trees for Structuring Sounds."

Similar presentations


Ads by Google