Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Intro_Java_brief_Liang2011.pdf
Скачиваний:
194
Добавлен:
26.03.2016
Размер:
10.44 Mб
Скачать

692 Chapter 20 Recursion

Video Note

Fractal (Sierpinski triangle)

20.8 Problem: Fractals

A fractal is a geometrical figure, but unlike triangles, circles, and rectangles, fractals can be divided into parts, each a reduced-size copy of the whole. There are many interesting examples of fractals. This section introduces a simple fractal, the Sierpinski triangle, named after a famous Polish mathematician.

A Sierpinski triangle is created as follows:

1.Begin with an equilateral triangle, which is considered to be a Sierpinski fractal of order (or level) 0, as shown in Figure 20.9(a).

2.Connect the midpoints of the sides of the triangle of order 0 to create a Sierpinski triangle of order 1 (Figure 20.9(b)).

3.Leave the center triangle intact. Connect the midpoints of the sides of the three other triangles to create a Sierpinski triangle of order 2 (Figure 20.9(c)).

4.You can repeat the same process recursively to create a Sierpinski triangle of order 3, 4,

Á, and so on (Figure 20.9(d)).

(a) Order 0

(b) Order 1

JPanel

JPanel

(c) Order 2

(d) Order 3

FIGURE 20.9 A Sierpinski triangle is a pattern of recursive triangles.

The problem is inherently recursive. How do you develop a recursive solution for it? Consider the base case when the order is 0. It is easy to draw a Sierpinski triangle of order 0. How do you draw a Sierpinski triangle of order 1? The problem can be reduced to drawing three Sierpinski triangles of order 0. How do you draw a Sierpinski triangle of order 2? The problem can be reduced to drawing three Sierpinski triangles of order 1. So the problem of drawing a Sierpinski triangle of order n can be reduced to drawing three Sierpinski triangles of order n - 1.

Listing 20.9 gives a Java applet that displays a Sierpinski triangle of any order, as shown in Figure 20.9. You can enter an order in a text field to display a Sierpinski triangle of the specified order.

LISTING 20.9 SierpinskiTriangle.java

1 import javax.swing.*;

2 import java.awt.*;

3 import java.awt.event.*;

20.8 Problem: Fractals 693

4

5 public class SierpinskiTriangle extends JApplet {

6 private JTextField jtfOrder = new JTextField("0", 5); // Order

7private SierpinskiTrianglePanel trianglePanel =

8 new SierpinskiTrianglePanel(); // To display the pattern

9

10public SierpinskiTriangle() {

11// Panel to hold label, text field, and a button

12JPanel panel = new JPanel();

13panel.add(new JLabel("Enter an order: "));

14panel.add(jtfOrder);

15jtfOrder.setHorizontalAlignment(SwingConstants.RIGHT);

17// Add a Sierpinski triangle panel to the applet

18add(trianglePanel);

19add(panel, BorderLayout.SOUTH);

21// Register a listener

22

jtfOrder.addActionListener(new ActionListener() {

 

listener

23

public void actionPerformed(ActionEvent e) {

 

24

trianglePanel.setOrder(Integer.parseInt(jtfOrder.getText()));

set a new order

25}

26});

27}

28

29static class SierpinskiTrianglePanel extends JPanel {

30private int order = 0;

31

32/** Set a new order */

33public void setOrder(int order) {

34this.order = order;

35repaint();

36}

37

38protected void paintComponent(Graphics g) {

39super.paintComponent(g);

40

 

 

 

 

41

// Select three points in proportion to the panel size

 

42

 

Point p1 = new Point(getWidth() / 2, 10);

 

three initial points

43Point p2 = new Point(10, getHeight() - 10);

44Point p3 = new Point(getWidth() - 10, getHeight() - 10);

46displayTriangles(g, order, p1, p2, p3);

47

}

48

 

49private static void displayTriangles(Graphics g, int order,

50Point p1, Point p2, Point p3) {

51if (order >= 0) {

52// Draw a triangle to connect three points

53

g.drawLine(p1.x, p1.y, p2.x, p2.y);

draw a triangle

54g.drawLine(p1.x, p1.y, p3.x, p3.y);

55g.drawLine(p2.x, p2.y, p3.x, p3.y);

57// Get the midpoint on each edge in the triangle

58Point p12 = midpoint(p1, p2);

59Point p23 = midpoint(p2, p3);

60Point p31 = midpoint(p3, p1);

62// Recursively display three triangles

63

displayTriangles(g, order - 1, p1, p12, p31);

top subtriangle

694 Chapter 20

Recursion

 

 

 

 

 

left subtriangle

64

 

 

displayTriangles(g, order - 1, p12, p2, p23);

 

right subtriangle

65

 

 

displayTriangles(g, order - 1, p31, p23, p3);

 

 

66

 

}

 

 

 

 

67

 

}

 

 

 

 

68

 

 

 

 

 

 

69

 

private static Point midpoint(Point p1, Point p2) {

 

70

 

return new Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);

 

71

 

}

 

 

 

 

72

 

}

 

 

 

main method omitted

73

}

 

 

 

 

The initial triangle has three points set in proportion to the panel size (lines 42–44). The displayTriangles(g, order, p1, p2, p3) method (lines 49–67) performs the following tasks if order >= 0:

1.Display a triangle to connect three points p1, p2, and p3 in lines 53–55 , as shown in Figure 20.10(a).

2.Obtain a midpoint between p1 and p2 (line 58), a midpoint between p2 and p3 (line 59), and a midpoint between p3 and p1 (line 60), as shown in Figure 20.10(b).

3.Recursively invoke displayTriangles with a reduced order to display three smaller Sierpinski triangles (lines 63–66). Note each small Sierpinski triangle is structurally identical to the original big Sierpinski triangle except that the order of a small triangle is one less, as shown in Figure 20.10(b).

A Sierpinski triangle is displayed in a SierpinskiTrianglePanel. The order property in the inner class SierpinskiTrianglePanel specifies the order for the Sierpinski triangle. The Point class, introduced in §16.10, “Mouse Events,” represents a point on a component. The midpoint(Point p1, Point p2) method returns the midpoint between p1 and p2 (lines 72–74).

p1 Draw the Sierpinski triangle displayTriangles(g, order, p1, p2, p3)

p2

(a)

p1

p3

Recursively draw the small Sierpinski triangle displayTriangles(g,

order - 1, p1, p12, p31)

Recursively draw the small

p12

p31

 

 

Sierpinski triangle

 

 

displayTriangles(g,

 

 

order - 1, p12, p2, p23)

 

 

p2

p3

p23

(b)

Recursively draw the small Sierpinski triangle displayTriangles(g,

order - 1, p31, p23, p3)

FIGURE 20.10 Drawing a Sierpinski triangle spawns calls to draw three small Sierpinski triangles recursively.

20.9 Problem: Eight Queens 695

20.9 Problem: Eight Queens

This section gives a recursive solution to the Eight Queens problem presented at the beginning of the chapter. The task is to find a solution to place a queen in each row on a chessboard such that no two queens can attack each other. You may use a two-dimensional array to represent a chessboard. However, since each row can have only one queen, it is sufficient to use a one-dimensional array to denote the position of the queen in the row. So, you may define array queens as follows:

int[] queens = new int[8];

Assign j to queens[i] to denote that a queen is placed in row i and column j. Figure 20.11(a) shows the contents of array queens for the chessboard in Figure 20.11(b).

queens[0] 0 queens[1] 4 queens[2] 7 queens[3] 5 queens[4] 2 queens[5] 6 queens[6] 1 queens[7] 3

(a)

(b)

FIGURE 20.11 queens[i] denotes the position of the queen in row i.

Listing 20.10 gives the program that displays a solution for the Eight Queens problem.

LISTING 20.10 EightQueens.java

1 import java.awt.*;

2 import javax.swing.*;

3

4 public class EightQueens extends JApplet {

5 public static final int SIZE = 8; // The size of the chessboard 6 private int[] queens = new int[SIZE]; // Queen positions

7

8public EightQueens() {

9

search(0); // Search for a solution from row 0

search for solution

10add(new ChessBoard(), BorderLayout.CENTER); // Display solution

11}

12

 

 

 

 

 

13

/** Check if a queen can be

placed at row i and column j */

 

14

 

private boolean isValid(int

row, int column) {

 

check whether valid

15for (int i = 1; i <= row; i++)

16if (queens[row - i] == column // Check column

17|| queens[row - i] == column - i // Check upleft diagonal

18|| queens[row - i] == column + i) // Check upright diagonal

19return false; // There is a conflict

20return true; // No conflict

21}

22

 

 

 

 

23

/** Search for a solution starting from a specified row */

 

24

 

private boolean search(int row) {

 

search this row

25

 

if (row == SIZE) // Stopping condition

 

26

 

return true; // A solution found to place 8 queens in 8 rows

search columns

27

 

 

 

 

28

 

for (int column = 0; column < SIZE; column++) {

search next row

696 Chapter 20 Recursion

 

29

 

queens[row] = column; // Place a queen at (row, column)

 

30

 

if (isValid(row, column) &&

search(row + 1)

)

found

31

 

return true; // Found, thus return true to exit for loop

 

32

 

}

 

 

 

33

 

 

 

 

 

34

 

// No solution for a queen placed at any column of this row

 

35

 

return false;

 

36

 

}

 

 

 

37

 

 

 

 

 

38

 

class ChessBoard extends JPanel {

 

39

 

private Image queenImage =

 

40

 

new ImageIcon("image/queen.jpg").getImage();

 

41

 

 

 

 

 

42

 

ChessBoard() {

 

43

 

this.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));

 

44

 

}

 

 

 

45

 

 

 

 

 

46

 

protected void paintComponent(Graphics g) {

 

47

 

super.paintComponent(g);

 

48

 

 

 

 

 

49

 

// Paint the queens

 

50

 

for (int i = 0; i < SIZE; i++) {

 

51

 

int j = queens[i]; // The position of the queen in row i

 

52

 

g.drawImage(queenImage, j * getWidth() / SIZE,

 

53

 

i * getHeight() / SIZE, getWidth() / SIZE,

 

54

 

getHeight() / SIZE, this);

 

55

 

}

 

 

 

56

 

 

 

 

 

57

 

// Draw the horizontal and vertical lines

 

58

 

for (int i = 1; i < SIZE; i++) {

 

59

 

g.drawLine(0, i * getHeight() / SIZE,

 

60

 

getWidth(), i * getHeight() / SIZE);

 

61

 

g.drawLine(i * getWidth() / SIZE, 0,

 

62

 

i * getWidth() / SIZE, getHeight());

 

63

 

}

 

 

 

64

 

}

 

 

 

65

 

}

 

 

main method omitted

66

}

 

 

 

The program invokes search(0) (line 9) to start a search for a solution at row 0, which recursively invokes search(1), search(2), Á , and search(7) (line 30).

The recursive search(row) method returns true if all row are filled (lines 25–26). The method checks whether a queen can be placed in column 0, 1, 2, Á , and 7 in a for loop (line 28). Place a queen in the column (line 29). If the placement is valid, recursively search for the next row by invoking search(row + 1) (line 30). If search is successful, return true (line 31) to exit the for loop. In this case, there is no need to look for the next column in the row. If there is no solution for a queen to be placed on any column of this row, the method returns false (line 35).

Suppose you invoke search(row) for row 3, as shown in Figure 20.12(a). The method tries to fill in a queen in column 0, 1, 2, and so on in this order. For each trial, the isValid(row, column) method (line 30) is called to check whether placing a queen at the specified position causes a conflict with the queens placed earlier. It ensures that no queen is placed in the same column (line 16), no queen is placed in the upper left diagonal (line 17), and no queen is placed in the upper right diagonal (line 18), as shown in Figure 20.12(a). If isValid(row, column) returns false, check the next column, as shown Figure 20.12(b). If isValid(row, column) returns true, recursively invoke search(row + 1), as shown in Figure 20.12(d). If search(row + 1) returns false, check the next column on the preceding row, as shown Figure 20.12(c).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]