티스토리 뷰
※ 목차
-컬렉션 프레임워크
-List<E> : ArrayList<E>, Vector<E>, LinkedList<E>
1. 컬렉션 프레임워크(Collection Framework)
(1) 컬렉션
동일한 타입을 묶어서 관리하는 자료구조.
저장 공간의 크기(capacity)를 동적관리. 데이터 변경(추가/삭제)에 따른 크기 변동.
↔ 배열
동일한 타입만 묶어서 저장하여 관리. 생성 시 크기가 정해지면 변경 불가.
(2) 프레임워크
클래스와 인터페이스의 모임(라이브러리). 클래스의 정의 + 설계의 원칙 또는 구조
(3) 컬렉션 프레임워크
리스트(List), 스택(Stack), 큐(Queue), 트리(Tree)등의 자료 구조에 정렬, 탐색 등의 알고리즘을 구조화 해놓은 프레임워크
인터페이스 - Collection<E> | |||
인터페이스 → | List<E> | Set<E> | Map<K, V> |
구현 클래스 → |
ArrayList<E> Vector<E> LinkedList<E> |
HashSet<E> LinkedHashSet<E> TreeSet<E> |
HashMap<K, V> LinkedHashMap<K, V> HashTable<K, V> TreeMap<K, V> |
웹 할 때 주로 ArrayList<E>, Vector<E> 사용하고 HashMap<K, V>도 종종.
List<E> 요약
-인덱스 번호로 접근 가능
ArrayList<E> | Vector<E> | LinkedList<E> |
동일한 객체 수집(Collection), 메모리 동적할당, 데이터 추가/변경/삭제 등의 메소드 |
index 정보 없음. 데이터 검색 속도 느림. 데이터 변경(추가/삭제) 적합. |
|
모든 메소드가 동기화(synchronized) 메소드로 구현 멀티스레드 적합 |
웹 프로그램에서 DB의 데이터를 가져와서 뿌리는 것을 많이함. ArrayList, Vector 적합.
멀티스레드할 때, 벡터를 공유해서 동기화.
1. List<E> 컬렉션
-인터페이스 List 구현 클래스 : ArrayList, Vector, LinkedList
-인덱스 번호로 접근 가능
-저장공간의 크기 동적 변환 : 데이터 변경에 따라 저장공간 변동. ↔ 배열과 비교 : 크기가 정해지면 변경 불가능.
(1) 리스트 생성
기본생성자의 경우 원소 10개를 저장할 수 있는 저장공간(capacity) 확보. 저장공간은 메모리 공간만을 의미하며 컬렉션의 크기(size)와는 무관하다.
추후 원소가 많아지면 저장공간을 자동 추가. 생성자 매개변수로 저장공간의 크기를 직접 넘겨줄 수 있다. (단, LinkedList는 제외. 저장공간 확보하지 않음)
(2-1) List interface의 구현 클래스 생성자
데이터 추가/삭제 가능한 동적 컬렉션 생성
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ListTest {
public static void main(String[] args) {
List<Integer> aList1 = new ArrayList<Integer>(); //1
List<Integer> aList2 = new ArrayList<Integer>(30); //2
List<String> aList3 = new Vector<String>(); //1
List<Double> aList4 = new Vector<Double>(30); //2
List<String> aList5 = new LinkedList<String>(); //1
//List<String> aList6 = new LinkedList<String>(30); //3 error - LinkedList
}
}
① 크기 지정하지 않으면 기본값으로 원소 10개 저장할 수 있는 저장공간 확보. 원소가 많아지면 자동으로 저장공간 추가. 컬렉션크기와 무관. ② 생성자 매개변수로 저장공간의 크기를 직접 넘겨줄 수 있다. ③ 단 LinkedList는 크기 지정 불가.
(2-2) Arrays.asList(...) 메서드
데이터 추가/삭제가 불가능한 정적 컬렉션 생성(데이터 변경(set()은 가능)
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ListTest {
public static void main(String[] args) {
// 이렇게 객체 만들면 크기변경 불가.
List<Integer> aList7 = Arrays.asList(1,2,3,4,5); //데이터변경은 되나 크기 변경은 불가.
List<String> aList8 = Arrays.asList("hello", "java");
}
}
(2) List<E> 공통 특성 메소드
-element(원소, 원소값)
-변수명.메소드(); 형태로 연결한다.
데이터 추가 | |||
add(element) | add(index, element) | addAll(element) | addAll(index, element) |
맨끝에 element를 추가 |
인덱스 번호에 element 추가 |
맨끝에 컬렉션 추가 |
인덱스 번호에 컬렉션 추가 |
데이터 변경 | 데이터 제거 | ||
set(index, element) | remove(index) | remove(Object o) | clear() |
인덱스 위치의 원소값 변경 |
인덱스 위치의 원소값 삭제 |
매개변수와 동일한 객체 삭제 |
원소값 전체 삭제 |
리스트 크기 | 값 가져오기 |
size() | get(indext) |
리스트 크기 | 인덱스 위치의 원소값 가져와 리턴 |
*위의 메소드들은 List뿐만 아니라 Set<E>, HashMap<E>, Stack<E>, Queue<E>에서도 거의 통용.
(2-1) 데이터 입력 add()
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ListTest {
public static void main(String[] args) {
List<Integer> aList1 = new ArrayList<Integer>();
List<Integer> aList2 = new ArrayList<Integer>(30);
List<String> aList3 = new Vector<String>();
List<Double> aList4 = new Vector<Double>(30);
List<String> aList5 = new LinkedList<String>(); //크기 지정 불가
// 이렇게 객체 만들면 크기변경(데이터 추가/삭제) 불가.
List<Integer> aList7 = Arrays.asList(1,2,3,4,5);
List<String> aList8 = Arrays.asList("hello", "java");
//데이터 입력
aList1.add(10); aList1.add(20);
System.out.println(aList1); //toString이 생략되어 있는 것.
aList3.add("java");
System.out.println(aList3);
aList4.add(10.0);
System.out.println(aList4);
aList5.add("java!!");
System.out.println(aList5);
//Array.asList 출력
System.out.println(aList7);
System.out.println(aList8);
//Array.asList 데이터 변경
aList7.set(1, 10); //인덱스 1번의 값을 10으로 바꿈
aList7.add(1); //데이터 추가 불가. 실행오류로 출력할 때 오류 발생함.
System.out.println(aList7); //실행오류
}
}
└출력 불가 : 데이터값 추가 불가한 곳에 데이터 추가해서 실행 때 오류 발생한 것.
(2-2) 데이터 추가/변경/삭제 add() / set() / remove()
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ListTest {
public static void main(String[] args) {
List<Integer> aList1 = new ArrayList<Integer>();
List<Integer> aList2 = new ArrayList<Integer>(30);
aList1.add(10); aList1.add(20);
//데이터 추가
aList1.add(30); // 10, 20, 30
aList1.add(0, 40); //40, 10, 20, 30
//데이터 추가 - 인덱스 번호에 값 추가
aList1.addAll(aList7); //40, 10, 20, 30, 1, 2, 3, 4, 5
//데이터 추가 - 리스트 객체 추가
aList1.addAll(1, aList7); //40, 1, 2, 3, 4, 5, 10, 20, 30, 1, 2, 3, 4, 5
//인덱스 1번 위치에 리스트 aList7 값 추가
//데이터 변경
aList1.set(1, 100); //40, 100, 2, 3, 4, 5, 10, 20, 30, 1, 2, 3, 4, 5
//데이터 삭제
aList1.remove(0); //100, 2, 3, 4, 5, 10, 20, 30, 1, 2, 3, 4, 5
//인덱스 0번 값 지움
//aList1.remove(100); //error : 인덱스번호인지 값인지 애매해서? 그 인덱스 번호가 없어서?
aList1.remove((Integer)100); //2, 3, 4, 5, 10, 20, 30, 1, 2, 3, 4, 5
// Integer 값이 100인 거 삭제
aList1.remove(new Integer(10)); //2, 3, 4, 5, 20, 30, 1, 2, 3, 4, 5
//값이 10 삭제
System.out.println(aList1); //toString이 생략되어 있는 것.
//데이터 가져오기
System.out.println(aList1.get(0)); //2
//인덱스0번값 가져옴
//데이터 출력 - for문 이용
for(int i=0; i<aList1.size(); i++) {
System.out.print(aList1.get(i)+" "); //2 3 4 5 20 30 1 2 3 4 5
}System.out.println();
//리스트 크기
System.out.println(aList1.size()); // 크기 12
//리스트 비어있는지 여부 확인 - true | false 리턴
System.out.println(aList1.isEmpty()); // false
}
}
(2-3) 배열 변환 toArray
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ListTest {
public static void main(String[] args) {
List<Integer> aList1 = new ArrayList<Integer>();
//배열로 변환
// Object[] a = aList1.toArray(); //Object형 타입의 배열로 변환
// System.out.println(a.toString());
Integer[] a = aList1.toArray(new Integer[0]); //원래 크기만큼 생성
System.out.println(Arrays.toString(a)); //출력
Integer[] b = aList1.toArray(new Integer[30]); //30만큼 만들고 값 없는 곳은 null채움.
System.out.println(b.toString(b));
}
}
(3) List<E> 컬렉션 - ArrayList<E>
위의 연습 예제, 예시들이 ArrayList<E>로 한 예제
(4) List<E> 컬렉션 - Vect<E>
-사용자정의 클래스로 연습 : ArrayList<E> 생성 → Vector<E> 생성
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
public class ExUser {
public static void main(String[] args) {
ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(1, "미미", "조리", new int[] {88,80,77}));
studentList.add(new Student(2, "로빈", "건축", new int[] {99,90,79}));
studentList.add(new Student(3, "샌디", "기공", new int[] {66,99,89}));
studentList.add(new Student(4, "쿠만", "토목", new int[] {70,79,89}));
studentList.add(new Student(5, "다이", "연금", new int[] {77,88,99}));
System.out.println(studentList);
System.out.println(studentList.get(0)); //index 0
for(Student s:studentList) { // studentList 출력
System.out.println(s);
}
System.out.println("===========================");
//Vector
Vector<Student> stdV = new Vector<Student>();
stdV.add(new Student(5, "미미", "조리", new int[] {88,80,77}));
stdV.add(new Student(4, "로빈", "건축", new int[] {99,90,79}));
stdV.add(new Student(3, "샌디", "기공", new int[] {66,99,89}));
stdV.add(new Student(2, "쿠만", "토목", new int[] {70,79,89}));
stdV.add(new Student(1, "다이", "연금", new int[] {77,88,99}));
System.out.println(stdV.get(4));
for(Student s:stdV) {
System.out.println(s);
}
System.out.println("===========================");
//데이터변경
stdV.set(3, new Student(1, "메리", "경영", new int[] {89,79,69}));
for(Student s:stdV) {
System.out.println(s);
}
System.out.println("===========================");
//데이터삭제
stdV.remove(0);
for(Student s:stdV) {
System.out.println(s);
}
System.out.println("===========================");
//배열 변환
Student[] arrstd = stdV.toArray(new Student[0]);
System.out.println(Arrays.toString(arrstd));
for(Student s : arrstd) {
System.out.println(s);
}
}
}
└studentList.add(new Student(1, "미미", "조리", new int[] {88,80,77}));
생성자 매개변수에 따른 데이터 입력. 배열을 생성해 매개인자로 넘기기.
[1, 미미, 조리, [88, 80, 77], 2, 로빈, 건축, [99, 90, 79], 3, 샌디, 기공, [66, 99, 89], 4, 쿠만, 토목, [70, 79, 89], 5, 다이, 연금, [77, 88, 99]]
1, 미미, 조리, [88, 80, 77]
1, 미미, 조리, [88, 80, 77]
2, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
4, 쿠만, 토목, [70, 79, 89]
5, 다이, 연금, [77, 88, 99]
===========================
1, 다이, 연금, [77, 88, 99]
5, 미미, 조리, [88, 80, 77]
4, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
2, 쿠만, 토목, [70, 79, 89]
1, 다이, 연금, [77, 88, 99]
===========================
5, 미미, 조리, [88, 80, 77]
4, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
1, 메리, 경영, [89, 79, 69]
1, 다이, 연금, [77, 88, 99]
===========================
4, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
1, 메리, 경영, [89, 79, 69]
1, 다이, 연금, [77, 88, 99]
===========================
[4, 로빈, 건축, [99, 90, 79], 3, 샌디, 기공, [66, 99, 89], 1, 메리, 경영, [89, 79, 69], 1, 다이, 연금, [77, 88, 99]]
4, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
1, 메리, 경영, [89, 79, 69]
1, 다이, 연금, [77, 88, 99]
-수업시간 예제) 똑같은데 이름만 다른 거
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
public class ArrayListTest {
public static void main(String[] args) {
// List<Student> studentList = new ArrayList<Student>(); 위아래 중 어느 것을 써도 상관없음.
ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(1, "홍길동", "컴공", new int[] {85,80,75})); //생성자 매개변수에 따른 데이터 입력
studentList.add(new Student(2, "홍길진", "멀티", new int[] {90,85,50})); //배열을 생성해 바로 매개인자로 넘기는 방식.
studentList.add(new Student(3, "홍길수", "정통", new int[] {50,60,90}));
studentList.add(new Student(4, "홍길미", "컴공", new int[] {80,90,70}));
studentList.add(new Student(5, "홍길민", "정통", new int[] {00,70,90}));
System.out.println(studentList);
System.out.println(studentList.get(0)); //값 가져오기
for(int i=0; i<studentList.size(); i++) {
System.out.println(studentList.get(i));
}
//Vector
List<Student> stdV = new Vector<Student>();
stdV.add(new Student(1, "홍길동", "컴공", new int[] {85,80,75})); //생성자 매개변수에 따른 데이터 입력
stdV.add(new Student(2, "홍길진", "멀티", new int[] {90,85,50}));
stdV.add(new Student(3, "홍길수", "정통", new int[] {50,60,90}));
stdV.add(new Student(4, "홍길미", "컴공", new int[] {80,90,70}));
stdV.add(new Student(5, "홍길민", "정통", new int[] {00,70,90}));
System.out.println(stdV);
System.out.println(stdV.get(0)); //값 가져오기
for(int i=0; i<stdV.size(); i++) {
System.out.println(stdV.get(i));
}
//데이터변경
System.out.println("==========");
//내용바꾸려면 student 객체 생성해 만들면 됨. 생성자 매개변수 종류, 순서, 개수에 맞게 데이터입력.
stdV.set(4, new Student(10, "박경미", "컴공", new int[] {55,66,77}));
for(int i=0; i<stdV.size(); i++) {
System.out.println(stdV.get(i));
}
//데이터 삭제
System.out.println("==========");
stdV.remove(0); //인덱스0번 삭제
for(int i=0; i<stdV.size(); i++) {
System.out.println(stdV.get(i));
}
//배열 변환
System.out.println("==========");
Student[] arrstd = stdV.toArray(new Student[0]);
System.out.println(Arrays.toString(arrstd)); //toString으로 출력
for(Student s:arrstd) { //for-each문
System.out.println(s); //for문 출력
}
}
}
(5) List<E> 컬렉션 - LinkedList<E>
-크기 설정 불가.
-장점 : 잘게 쪼개진 데이터를 찾아가며 데이터 저장. 새로운 데이터를 데이터 중간에 끼워넣고 삭제하는데 적합. 링크만 변경하면 되기 때문에.
ArrayList, Vector는 데이터 추가/삭제할 때 데이터 변경에 따른 데이터를 뒤로 밀고, 앞으로 당기기 발생하며 크기가 늘었다 줄었다 함. (시간 소요) 반대로 데이터를 순차적으로 가져오고 수정을 별로 하지 않을 경우 적합.
-예시) 생성 및 데이터 추가/삭제
package aa;
import java.util.LinkedList;
public class ExLinkedList {
public static void main(String[] args) {
LinkedList<Student> linkedList = new LinkedList<Student>();
linkedList.add(new Student(1, "미미", "조리", new int[] {88,80,77}));
linkedList.add(new Student(2, "로빈", "건축", new int[] {99,90,79}));
linkedList.add(new Student(3, "샌디", "기공", new int[] {66,99,89}));
linkedList.add(new Student(4, "쿠만", "토목", new int[] {70,79,89}));
linkedList.add(new Student(5, "다이", "연금", new int[] {77,88,99}));
// System.out.println(linkedList); //일렬로 주욱 출력
for(Student s : linkedList) {
System.out.println(s);
}
System.out.println("==========데이터수정==========");
//데이터수정
linkedList.set(3, new Student(4, "톰슨", "철학", new int[] {69,93,79}));
for(Student s : linkedList) {
System.out.println(s);
}
System.out.println("==========데이터제거==========");
//데이터제거
linkedList.remove(0);
for(int i=0; i<linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
}
}
-결과 출력(console)
1, 미미, 조리, [88, 80, 77]
2, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
4, 쿠만, 토목, [70, 79, 89]
5, 다이, 연금, [77, 88, 99]
==========데이터수정==========
1, 미미, 조리, [88, 80, 77]
2, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
4, 톰슨, 철학, [69, 93, 79]
5, 다이, 연금, [77, 88, 99]
==========데이터제거==========
2, 로빈, 건축, [99, 90, 79]
3, 샌디, 기공, [66, 99, 89]
4, 톰슨, 철학, [69, 93, 79]
5, 다이, 연금, [77, 88, 99]
-수업시간예제) 이름만 다르고 같음.
package aa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
public class ArrayListTest {
public static void main(String[] args) {
List<Student> linkedList = new LinkedList<Student>();
linkedList.add(new Student(1, "홍길동", "컴공", new int[] {85,80,75})); //생성자 매개변수에 따른 데이터 입력
linkedList.add(new Student(2, "홍길진", "멀티", new int[] {90,85,50})); //배열을 생성해 바로 매개인자로 넘기는 방식.
linkedList.add(new Student(3, "홍길수", "정통", new int[] {50,60,90}));
linkedList.add(new Student(4, "홍길미", "컴공", new int[] {80,90,70}));
linkedList.add(new Student(5, "홍길민", "정통", new int[] {00,70,90}));
for(int i=0; i<linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
//데이터 수정
linkedList.set(0, new Student(11, "aaa", "bbb", new int[] {100, 90, 80}));
System.out.println("==========");
for(int i=0; i<linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
System.out.println("==========");
//delete
linkedList.remove(0);
for(Student s:linkedList) { //for-each문
System.out.println(s); //for문 출력
}
System.out.println("==========");
}
}
3. ArrayList와 LinkedList 공통점, 차이점
(+어레이리스트와 벡터의 차이점은 벡터가 동기화된다는 것뿐.)
ArrayList | LinkedList |
데이터 추가/삭제 느림 | 데이터 추가/삭제 빠름 |
검색 속도 빠름 | 검색 속도 느림 |
└ArrayList : 데이터 변경에 따라 데이터가 밀리거나 당기기 때문에 데이터 추가/삭제 속도가 느림.
└LinkedList : 데이터 변경에 따라 연결된 링크만 변경해주면 되기 때문에 데이터추가/삭제 속도 빠름.
(1) 속도 알아보기
-데이터 추가, 삭제, 검색할 때, (숫자가 클수록 처리 속도 늘어남. )
package aa;
import java.util.ArrayList;
import java.util.LinkedList;
public class LinkedListVSArrayList {
public static void main(String[] args) {
//기본 데이터형 불가↓ Object로부터 상속받은 클래스형만 사용 가능. Integer, Double, ...
ArrayList<Integer> aList = new ArrayList<Integer>();
LinkedList<Integer> lList = new LinkedList<Integer>();
long startTime = System.nanoTime();
for(int i=0; i<100000; i++) {
aList.add(0, 1);
}
long endTime = System.nanoTime();
System.out.println("ArrayList 데이터 추가시간 : "+(endTiem - startTiem));
startTime = System.nanoTime(); //앞에서 정의하고 새로운 값 대입.
for(int i=0; i<100000; i++) {
lList.add(0, 1);
}
endTime = System.nanoTime();
System.out.println("LinkedList 데이터 추가시간 : "+(endTiem - startTiem));
System.out.println("=======================");
//데이터 검색
startTime = System.nanoTime();
for(int i=0; i<100000; i++) {
aList.get(i);
}
endTime = System.nanoTime();
System.out.println("ArrayList 데이터 검색 시간 : "+(endTiem - startTiem));
startTime = System.nanoTime(); //앞에서 정의하고 새로운 값 대입.
for(int i=0; i<100000; i++) {
lList.get(i);
}
endTime = System.nanoTime();
System.out.println("LinkedList 데이터 검색 시간 : "+(endTiem - startTiem));
System.out.println("=======================");
//데이터 제거 시간
//데이터 입력이 되어 있어야 삭제할 게 있음. 위의 데이터 입력 과정 필요.
startTime = System.nanoTime();
for(int i=0; i<100000; i++) {
aList.remove(0);
}
endTime = System.nanoTime();
System.out.println("ArrayList 데이터 삭제시간 : "+(endTiem - startTiem));
startTiem = System.nanoTime(); //앞에서 정의하고 새로운 값 대입.
for(int i=0; i<100000; i++) {
lList.remove(0);
}
endTime = System.nanoTime();
System.out.println("LinkedList 데이터 삭제시간 : "+(endTiem - startTiem));
}//main
}
ArrayList 데이터 추가시간 : 4302647900 LinkedList 데이터 추가시간 : 8825500 ======================= ArrayList 데이터 검색 시간 : 3068700 LinkedList 데이터 검색 시간 : 33058478600 ======================= ArrayList 데이터 삭제시간 : 5128119400 LinkedList 데이터 삭제시간 : 12997500 |
ArrayList는 데이터 검색 속도가 빠르고 LinkedList는 데이터 추가/삭제 속도가 빠름을 알 수 있다.
'수업 > └Java' 카테고리의 다른 글
[CH16_3]Java IO(Input/Output) - char 단위 입출력 (0) | 2022.02.09 |
---|---|
[CH16_1]파일(File)과 문자셋(Charset) (0) | 2022.02.09 |
[CH12]Thread (0) | 2022.02.07 |
[실습문제6_1]Person, Customer, Test (0) | 2022.02.04 |
[CH10]이너클래스(innner class) (0) | 2022.02.04 |
- Total
- Today
- Yesterday
- border-spacing
- improt
- CascadingStyleSheet
- 기본선택자
- 입력양식
- html atrribute
- scanner
- BAEKJOON
- html input type
- text formatting
- ScriptTag
- css
- html
- html pre
- empty-cell
- 스크립태그
- JavaScript
- html layout
- initialized
- input type 종류
- html a tag
- caption-side
- typeof
- 변수
- A%B
- html base tag
- 외부구성요소
- 미디어 태그
- selcetor
- Java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |