월 화는 휴강
import java.util.Scanner;
public class Max2 {
// 세 정수 중 최댓값을 판단하는 메소드를 정의
static int maxJudge(int a, int b, int c) {
int max = a;
if (b > max) {
max = b;
}
if (c > max) {
max = c;
}
return max;
}
static int min3Judge(int a, int b, int c) {
int min = a;
if (b < min) {
min = b;
}
if (c < min) {
min = c;
}
return min;
}
static int min4Judge(int a, int b, int c, int d) {
int min = a;
if (b < min) {
min = b;
}
if (c < min) {
min = c;
}
if (d < min) {
min = d;
}
return min;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("네 정수의 최댓값을 구합니다.");
System.out.print("a의 값 입력: ");
int a = in.nextInt();
System.out.print("b의 값 입력: ");
int b = in.nextInt();
System.out.print("c의 값 입력: ");
int c = in.nextInt();
System.out.print("d의 값 입력: ");
int d = in.nextInt();
// maxJudge 메소드를 호출하여 최댓값을 계산하고 출력합니다.
int result = maxJudge(a, b, c);
System.out.println("최댓값: " + result);
result = min3Judge(a, b, c);
System.out.println("최솟값: " + result);
result = min4Judge(a, b, c, d);
System.out.println("최솟값: " + result);
}
}
import java.util.Scanner;
public class Main {
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
// 높이 입력 받기
int n = in.nextInt();
// 종류 입력받기
int m = in.nextInt();
if (n <= 100) {
if (1 <= m && m <= 3) {
switch (m) {
case 1: //1일때
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
break;
case 2: // 2일 때
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
System.out.print("*");
}
System.out.println();
}
break;
default: // 3일떄
for(int i=0;i<n;i++){
for(int j=i;j<n-1;j++){
System.out.print(" ");
}
for(int j=0;j<i*2+1;j++){
System.out.print("*");
}
System.out.println();
}
}
}
}
else {
System.out.println("INPUT ERROR");
}
}
}
public class StarEx
{
static void star01()
{
for (int i = 0; i < 4; i++)
{ // 행 출력
for (int j = 0; j < 4; j++)
{
System.out.print("*");
}
System.out.println();
}
}
static void star02()
{
for (int i = 0; i < 4; i++)
{
//빈칸의 갯수만큼 별 출력
for (int j = 0; j <= i; j++)
{
System.out.print("*");
}
System.out.println();
}
}
static void star03() {
for (int i = 0; i < 4; i++) //4줄 생성
{
//빈칸의 갯수만큼 별 출력
for (int j = 3; j >= 0; j--)
{
if(i<j) {
System.out.print(" ");
}else {
System.out.print("*");
}
}
System.out.println();
}
}
static void star04() {
for (int i = 4; i > 0 ; i--) //4줄 생성하면서 빈칸 하나씩 줄어들게 하기
{
//빈칸의 갯수만큼 별 출력
for (int j = 0; j < i; j++)
{
System.out.print("*");
}
System.out.println();
}
}
static void star05() {
for (int i = 0; i > 4 ; i++) //4줄 생성
{
//j가 i보다 작으면
for (int j = 0; j < i; j++)
{
System.out.print(" ");
}
for (int j = 3; j >= i; j--)
{
System.out.print("*");
}
System.out.println();
}
}
static void star06() {
for (int i = 0; i < 4 ; i++) //4줄 생성
{
//j가 i보다 작으면
for (int j = 0; j < 3-i; j++)
{
System.out.print(" ");
}
for (int j = 0; j <2*i+1; j++)
{
System.out.print("*");
}
System.out.println();
}
}
static void star07() {
for (int i = 0; i < 4 ; i++) //4줄 생성
{
//j가 i보다 작으면
for (int j = 1; j <=i; j++)
{
System.out.print(" ");
}
for (int j = 7; j >=i*2+1; j--)
{
System.out.print("*");
}
System.out.println();
}
}
public static void main(String[] args)
{
star01();
star02();
star03();
star04();
star05();
star06();
star07();
}
}
// int형 고정 길이 스택의 사용 예
import java.util.Scanner;
class IntStackTester {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
IntStack s = new IntStack(64); // 최대 64 개를 푸시할 수 있는 스택
while (true) {
System.out.println(); // 메뉴 구분을 위한 빈 행 추가
System.out.printf("현재 데이터 개수: %d / %d\n", s.size(), s.getCapacity());
System.out.print("(1)푸시 (2)팝 (3)피크 (4)덤프 (0)종료: ");
int menu = stdIn.nextInt();
if (menu == 0) break;
int x;
switch (menu) {
case 1: // 푸시
System.out.print("데이터: ");
x = stdIn.nextInt();
try {
s.push(x);
} catch (IntStack.OverflowIntStackException e) {
System.out.println("스택이 가득 찼습니다.");
}
break;
case 2: // 팝
try {
x = s.pop();
System.out.println("팝한 데이터는 " + x + "입니다.");
} catch (IntStack.EmptyIntStackException e) {
System.out.println("스택이 비어있습니다.");
}
break;
case 3: // 피크
try {
x = s.peek();
System.out.println("피크한 데이터는 " + x + "입니다.");
} catch (IntStack.EmptyIntStackException e) {
System.out.println("스택이 비어있습니다.");
}
break;
case 4: // 덤프
s.dump();
break;
}
}
}
}
// 원하는 개수만큼 값을 계속 입력받고, 요솟수가 N인 배열에 마지막 N개를 저장
import java.util.Scanner;
class LastNElements {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
final int N = 10;
int[] a = new int[N]; // 읽어 들인 값을 저장
int cnt = 0; // 읽어 들인 개수
int retry; // 다시 한 번?
System.out.println("정수를 입력하세요.");
do {
System.out.printf("%d번째 정수: ", cnt + 1);
a[cnt++ % N] = stdIn.nextInt();
System.out.print("계속 할까요? (Yes…1/No…0) : ");
retry = stdIn.nextInt();
} while (retry == 1);
int i = cnt - N;
if (i < 0) i = 0;
for ( ; i < cnt; i++)
System.out.printf("%2d번째 = %d\n", i + 1, a[i % N]);
}
}
// int형 고정 길이 스택
public class IntStack {
private int[] stk; // 스택용 배열
private int capacity; // 스택의 크기
private int ptr; // 스택 포인터
//--- 실행시 예외: 스택이 비어있음 ---//
public class EmptyIntStackException extends RuntimeException {
public EmptyIntStackException() { }
}
//--- 실행시 예외: 스택이 가득 참 ---//
public class OverflowIntStackException extends RuntimeException {
public OverflowIntStackException() { }
}
//--- 생성자(constructor) ---//
public IntStack(int maxlen) {
ptr = 0;
capacity = maxlen;
try {
stk = new int[capacity]; // 스택 본체용 배열을 생성
} catch (OutOfMemoryError e) { // 생성할 수 없음
capacity = 0;
}
}
//--- 스택에 x를 푸시 ---//
public int push(int x) throws OverflowIntStackException {
if (ptr >= capacity) // 스택이 가득 참
throw new OverflowIntStackException();
return stk[ptr++] = x;
}
//--- 스택에서 데이터를 팝(정상에 있는 데이터를 꺼냄) ---//
public int pop() throws EmptyIntStackException {
if (ptr <= 0) // 스택이 빔
throw new EmptyIntStackException();
return stk[--ptr];
}
//--- 스택에서 데이터를 피크(peek, 정상에 있는 데이터를 들여다봄) ---//
public int peek() throws EmptyIntStackException {
if (ptr <= 0) // 스택이 빔
throw new EmptyIntStackException();
return stk[ptr - 1];
}
//--- 스택을 비움 ---//
public void clear() {
ptr = 0;
}
//--- 스택에서 x를 찾아 인덱스(없으면 –1)를 반환 ---//
public int indexOf(int x) {
for (int i = ptr - 1; i >= 0; i--) // 꼭대기 쪽부터 선형 검색
if (stk[i] == x)
return i; // 검색 성공
return -1; // 검색 실패
}
//--- 스택의 크기를 반환 ---//
public int getCapacity() {
return capacity;
}
//--- 스택에 쌓여있는 데이터 갯수를 반환 ---//
public int size() {
return ptr;
}
//--- 스택이 비어있는가? ---//
public boolean isEmpty() {
return ptr <= 0;
}
//--- 스택이 가득 찼는가? ---//
public boolean isFull() {
return ptr >= capacity;
}
//--- 스택 안의 모든 데이터를 바닥 → 정상 순서로 표시 ---//
public void dump() {
if (ptr <= 0)
System.out.println("스택이 비어있습니다.");
else {
for (int i = 0; i < ptr; i++)
System.out.print(stk[i] + " ");
System.out.println();
}
}
}
import java.util.Scanner;
public class stack1 {
public static void main(String[] args) {
int n, i, data;
// 명령 i, o, c
String cmd;
// 스택
int[] stack = new int[100];
int nIndex = 0;
Scanner in = new Scanner(System.in);
// 명령의 수
n = Integer.parseInt(in.nextLine());
for (i = 0; i < n; i++) {
cmd = in.nextLine();
// insert
if ("i".equals(cmd.substring(0, 1))) {
data = Integer.parseInt(cmd.substring(2));
stack[nIndex++] = data;
}
// out
else if ("o".equals(cmd)) {
if (nIndex == 0) {
System.out.println("empty");
} else {
System.out.println(stack[--nIndex]);
}
}
// count
else if ("c".equals(cmd)) {
System.out.println(nIndex);
}
}
}
}
import java.util.Scanner;
public class stack2 {
private static int count() {
return nIndex;
}
private static void push(int data) {
stack[nIndex++] = data;
}
private static int pop() {
return stack[--nIndex];
}
private static boolean isEmpty() {
return nIndex == 0;
}
static int nIndex = 0; // 스택의 인덱스
static int[] stack = new int[100]; // 스택 배열
public static void main(String[] args) {
int n, i, data;
String cmd;
Scanner in = new Scanner(System.in);
n = Integer.parseInt(in.nextLine());
for (i = 0; i < n; i++) {
cmd = in.nextLine();
if ("i".equals(cmd.substring(0, 1))) {
data = Integer.parseInt(cmd.substring(2));
push(data);
} else if ("o".equals(cmd)) {
if (isEmpty()) {
System.out.println("empty");
} else {
System.out.println(pop());
}
} else if ("c".equals(cmd)) {
int num = count();
System.out.println(num);
}
}
}
}
import java.util.Scanner;
public class que {
private static Scanner in;
public static void main(String[] args){
in = new Scanner(System.in);
//queue
int queue[] = new int[100];
// 뒤
int rear = 0;
// 아ㅠ
int front = 0;
int n = in.nextInt();
String cmd;
// 개행문자 제거
in.nextLine();
for(int i=0; i<n; i++){
cmd = in.nextLine();
//insert
if('i'==(cmd.toCharArray()[0])){
queue[rear++] = Integer.parseInt(cmd.substring(2));
}
//out
else if("o".equals(cmd)){
if(queue[front]==0) System.out.println("empty");
else System.out.println(queue[front++]);
}
//count
else if("c".equals(cmd)){
System.out.println(rear-front);
}
}
}
}
// int형 고정 길이 큐
public class IntQueue {
private int[] que; // 큐용 배열
private int capacity; // 큐의 크기
private int front; // 맨 처음 요소 커서
private int rear; // 맨 끝 요소 커서
private int num; // 현재 데이터 개수
//--- 실행시 예외: 큐가 비어있음 ---//
public class EmptyIntQueueException extends RuntimeException {
public EmptyIntQueueException() { }
}
//--- 실행시 예외: 큐가 가득 찼음 ---//
public class OverflowIntQueueException extends RuntimeException {
public OverflowIntQueueException() { }
}
//--- 생성자(constructor) ---//
public IntQueue(int maxlen) {
num = front = rear = 0;
capacity = maxlen;
try {
que = new int[capacity]; // 큐 본체용 배열을 생성
} catch (OutOfMemoryError e) { // 생성할 수 없음
capacity = 0;
}
}
//--- 큐에 데이터를 인큐 ---//
public int enque(int x) throws OverflowIntQueueException {
if (num >= capacity)
throw new OverflowIntQueueException(); // 큐가 가득 찼음
que[rear++] = x;
num++;
if (rear == capacity)
rear = 0;
return x;
}
//--- 큐에서 데이터를 디큐 ---//
public int deque() throws EmptyIntQueueException {
if (num <= 0)
throw new EmptyIntQueueException(); // 큐가 비어있음
int x = que[front++];
num--;
if (front == capacity)
front = 0;
return x;
}
//--- 큐에서 데이터를 피크(프런트 데이터를 들여다봄) ---//
public int peek() throws EmptyIntQueueException {
if (num <= 0)
throw new EmptyIntQueueException(); // 큐가 비어있음
return que[front];
}
//--- 큐를 비움 ---//
public void clear() {
num = front = rear = 0;
}
//--- 큐에서 x를 검색하여 인덱스(찾지 못하면 –1)를 반환 ---//
public int indexOf(int x) {
for (int i = 0; i < num; i++) {
int idx = (i + front) % capacity;
if (que[idx] == x) // 검색 성공
return idx;
}
return -1; // 검색 실패
}
//--- 큐의 크기를 반환 ---//
public int getCapacity() {
return capacity;
}
//--- 큐에 쌓여 있는 데이터 개수를 반환 ---//
public int size() {
return num;
}
//--- 큐가 비어있는가? ---//
public boolean isEmpty() {
return num <= 0;
}
//--- 큐가 가득 찼는가? ---//
public boolean isFull() {
return num >= capacity;
}
//--- 큐 안의 모든 데이터를 프런트 → 리어 순으로 출력 ---//
public void dump() {
if (num <= 0)
System.out.println("큐가 비어있습니다.");
else {
for (int i = 0; i < num; i++)
System.out.print(que[(i + front) % capacity] + " ");
System.out.println();
}
}
}
// int형 고정 길이 큐의 사용 예
import java.util.Scanner;
class IntQueueTester {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
IntQueue s = new IntQueue(64); // 최대 64개를 인큐할 수 있는 큐
while (true) {
System.out.println(" "); // 메뉴 구분을 위한 빈 행 추가
System.out.printf("현재 데이터 개수: %d / %d\n", s.size(), s.getCapacity());
System.out.print("(1)인큐 (2)디큐 (3)피크 (4)덤프 (0)종료: ");
int menu = stdIn.nextInt();
if (menu == 0) break;
int x;
switch (menu) {
case 1: // 인큐
System.out.print("데이터: ");
x = stdIn.nextInt();
try {
s.enque(x);
} catch (IntQueue.OverflowIntQueueException e) {
System.out.println("큐가 가득 찼습니다.");
}
break;
case 2: // 디큐
try {
x = s.deque();
System.out.println("디큐한 데이터는 " + x + "입니다.");
} catch (IntQueue.EmptyIntQueueException e) {
System.out.println("큐가 비어 있습니다.");
}
break;
case 3: // 피크
try {
x = s.peek();
System.out.println("피크한 데이터는 " + x + "입니다.");
} catch (IntQueue.EmptyIntQueueException e) {
System.out.println("큐가 비어 있습니다.");
}
break;
case 4: // 덤프
s.dump();
break;
}
}
}
}
Array-vs-ArrayList-vs-LinkedList-차이
// 배열
Number[] numbers = {10, 20, 30, 40, 50};
System.out.println(Arrays.toString(numbers));
// 30값을 삭제, 배열은 따로 삭제 메서드가 없어서 null 추가
numbers[2] = null;
System.out.println(Arrays.toString(numbers));
// 크기를 따로 지정하지 않음
List<Number> list1 = new ArrayList<Number>(); //동적할당
list1.add(10);
list1.add(20);
list1.add(30);
list1.add(40);
list1.add(50);
System.out.println(list1.size()); //list의 크기값 반환, list에 담긴 요소의 개수
List<Number> list2 = new ArrayList<Number>();
list2.add(60);
list2.add(70);
list1.addAll(list2); //list1에 list2 추가
System.out.println(list1.size());
System.out.println(list1);
//list2에 80 삽입(index, data)
list2.add(80);
System.out.println(list2);
// 기존 자료는 뒤로 밀려나고 삭제되지 않는다.
list2.add(0, 100);
System.out.println(list2);
// 뒤로 밀어내는 동작을 하기 때문에 사이즈가 커질수록 비효율적
//list2.add(50, 200); //논리적인 공간을 넘어 접근하는 경우 발생
// 요소 삭제 : remove()
list2.remove(2);
System.out.println(list2);
// clear() : 요소 완전히 삭제
list2.clear();
System.out.println(list2);
// 요소 얻어내기 : Object get(index), List subList(int frontIndex,int totalIndex)
Number n = list1.get(0);
System.out.println(n);
//list1에서 40값을 출력
n = list1.get(3);
System.out.println(n);
System.out.println(list1.subList(0, 5)); // 40까지 출력
System.out.println(list1.subList(3, 5)); // 40,50
System.out.println(list1.subList(2, 6)); // 30,40, 50, 60
//요소 변경(update) : Object set(index, Object) 해당 인덱스의 데이터를 변경하여서 인덱스 변화 없으
list1.set(0, 500);
System.out.println(list1);
// 정수형 객체만 저장 가능한 ArrayList numbers1을 생성
ArrayList<Integer> numbers1 = new ArrayList<Integer>();
// 초기 용량(capacity) 지정 ArrayList numbers2 생성
ArrayList<Integer> number2 = new ArrayList<Integer>();
// 배열을 넣어 생성 ArrayList numbers3 생성 => 배열을 만든 것과 같음
ArrayList<Integer> number3 = new ArrayList<Integer>(Arrays.asList(10, 20, 30));
// 다른 컬렉션으로부터 그대로 요소를 받아와 생성 ArrayList numbers4 생성
ArrayList<Integer> number4 = new ArrayList<Integer>(number3);
//arrayList의 용량 운영 기능 : int size(), void ensureCapacity(최소값 지정), void trimToSize()
List<Number> list3 = new ArrayList<Number>(5); //용량 10을 설정 => 오버헤드를 줄일 수 있음
list3.add(1);
list3.add(2);
list3.add(3);
list3.add(4);
list3.add(5);
list3.add(6);
list3.add(7);
System.out.println(list3.size()); // 크기 7
List<Number> list4 = new ArrayList<Number>(5);
list4.add(1);
list4.add(2);
list4.add(3);
list4.add(4);
list4.add(5);
// Object에서 상속받은 clone 메소드
Object clonelist4 = ((ArrayList<Number>)list4).clone();
ArrayList list4_1 = (ArrayList) clonelist4;
System.out.println(list4_1.toString());
// 정렬 : void sort(Comparator c) 지정된 정렬기준으로 ArrayList 정렬(원본 리스트 자동)
List list5 = new ArrayList(5);
list5.add("3");
list5.add("2");
list5.add("1");
list5.add("4");
list5.add("5");
//오름차순 정렬
list5.sort(Comparator.naturalOrder());
System.out.println(list5.toString());
//내림차순 정렬
list5.sort(Comparator.reverseOrder());
System.out.println(list5); //Comparator 인터페이스 학습
// ArrayList 순회 : Iterator 인터페이스 활용
Iterator<Integer> it = list5.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
MyArrayList
클래스를 통해 리스트를 구현하고, 이를 테스트하는 MyList_Main
클래스를 제공add
, remove
, get
, set
메서드는 일부 구현되어 있으며, ListIterator
를 통해 리스트를 순회할 수 있도록 구현되어 있다.// ArrayList 클래스는 List인터페이스를 implements하여 구현한 클래스
// 직접 interface를 구현하고 추상메서드를 정의한 후 구현클래스에서 추상클래스를 구현해
// 봄으로써 ArrayList 코드 내부 동작원리 이해
public interface Mylist<T> {
boolean add(T value); //요소 추가
void add(int index, T value); //요소를 특정 위치에 추가
boolean remove(Object value); //요소를 삭제
T remove(int index); //특정 위치 요소 삭제
T get(int index); //위치의 요소를 가져오기
void set(int index, T value); //특정 위치에 있는 요소를 새 요소로 대체
boolean contains(Object value); // 특정 요소가 리스트에 있는지 여부를 확인
int indexOf(Object value); // 특정 요소가 몇 번째 위치에 있는지를 반환 (순차 검색)
int lastIndexOf(Object o); // 특정 요소가 몇 번째 위치에 있는지를 반환 (역순 검색)
int size(); // 요소의 개수를 반환
boolean isEmpty(); // 요소가 비어있는지
public void clear(); // 요소를 모두 삭제
}
MyListIterator
public interface MyListIterator<T>{
T next(); // next 메세드로 다음 요소 반환
boolean hasNext(); // hasNext로 다음 요소의 존재 여부 확인 가능
T previous();
boolean hasPrevios();
void add(Object element);
void remove();
}
import java.util.Arrays;
public class MyArrayList<E> implements Mylist<E> {
// 기본 용량 및 빈 배열 정의
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
// 배열의 총 개수(크기)와 데이터를 담을 배열 선언
private int size;
Object[] elementData;
// 기본 생성자: 용량을 기본값으로 초기화하고 크기를 0으로 설정
public MyArrayList() {
this.elementData = new Object[DEFAULT_CAPACITY];
this.size = 0;
}
// 용량을 직접 설정하는 생성자
public MyArrayList(int capacity) {
if (capacity > 0) {
this.elementData = new Object[capacity];
} else if (capacity == 0) {
this.elementData = new Object[DEFAULT_CAPACITY];
} else if (capacity < 0) {
// 음수 용량은 예외 처리
throw new RuntimeException(new IllegalAccessError("리스트 용량을 잘못 설정 : 음수값을 허용하지 않습니다."));
}
this.size = 0; // 초기 크기를 0으로 설정
}
// resize() : 리스트에 요소를 추가/삭제 동작할 떄 index가 기본적으로 조정되어야한다.
// 이를 위해 배열의 크기와 배열의 용량을 비교하여, 크기가 작은 경우 리사이징 처리하여 메모리를 최적화
public void resize(){
int element_capacity = elementData.length;
//용량이 꽉 찬 경우
if(element_capacity == size){
int new_capacity = element_capacity * 2;
elementData = Arrays.copyOf(elementData, new_capacity);
return;
}
// 용량에 비해 데이터양이 적은 경우
if((element_capacity/2)> size){
int half_capacity = element_capacity;
elementData = Arrays.copyOf(elementData, Math.max(half_capacity, DEFAULT_CAPACITY));
}
// 들어 있는 데이터가 없는 경우(빈 배열)
if(Arrays.equals(elementData, EMPTY_ELEMENTDATA)){
elementData = new Object[DEFAULT_CAPACITY]; //기본용량으로 초기화
}
}
@Override
public boolean add(E value) {
elementData[size] = value;
size++;
return true;
}
@Override
public void add(int index, E value) {
//인덱스가 음수이거나 배열 크기가(size)를 벗어난 경우 예외발생
if(index <0 || index > size){
throw new IndexOutOfBoundsException();
}
}
@Override
public boolean remove(Object value) {
return false;
}
@Override
public E remove(int index) {
return null;
}
@Override
public E get(int index) {
return null;
}
@Override
public void set(int index, E value) {
}
@Override
public String toString() {
return Arrays.toString(elementData);
}
class ListIterator implements MyListIterator<E>{
private int nextIndex = 0; //커서 위치
@Override
public E next() {
return (E) elementData[nextIndex++];
}
@Override
public boolean hasNext() {
return nextIndex < elementData.length;
}
}
public ListIterator listIterator(){
return new ListIterator();
}
}
public class MyList_Main {
public static void main(String[] args){
MyArrayList<Number> list = new MyArrayList<Number>(); //초기 용량이 10
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println(list.toString());
//list 이터레이터 반환
MyListIterator<Number> listit = list.listIterator();
while(listit.hasNext()){
System.out.println(listit.next());
}
}
}
public class Node<T> {
Node prev; //이전 노드 주소를 저장하는 필드 doubly linked list
Node next; //다음 노드 주소를 저장하는 필드 singly linked list
int data; //데이터를 저장하는 필드
}
LinkedListEx
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
public class LinkedListEx {
public static void main(String[] args){
//라이브러리에서 제공하는 생성자를 이용하여
LinkedList<Integer> list = new LinkedList<Integer>();
LinkedList<Integer> list2 = new LinkedList<Integer>(Arrays.asList(1, 2));
//문자열 "J" "A" "V" "A" 배열을 할당하여 list3 생성
LinkedList<String> list3 = new LinkedList<String>(Arrays.asList("J", "A", "V", "A"));
// addFirst(object) : ArrayList와 다르게 맨 앞에 데이터 추가 가능
// addLast(object)
//add(object), add(inedx, object), addAll(Collection c)
System.out.println(list3); //[J, A, V, A]
list3.addFirst("Perfect");
list3.addLast("Programming");
System.out.println(list3); //[Perfect, J, A, V, A, Programming]
list3.add("Backend14"); // [Perfect, J, A, V, A, Programming, Backend14]
// 순회해서 가지고 옴
Iterator<String> it = list3.iterator();
while (it.hasNext()){
System.out.print(it.next() + " "); //Perfect J A V A Programming Backend14
}
list3.removeFirst();
System.out.println(list3); //[J, A, V, A, Programming, Backend14]
list3.removeLast();
System.out.println(list3); //[J, A, V, A, Programming]
}
}
MySingleLinkedList
package Linkedlist;
import java.util.Objects;
//import Linkedlist.Node;
public class MySingleLinkedList<E> {
private Node<E> head; // 노드의 첫 부분을 가리키는 포인트
private Node<E> tail; // 노드의 마지막 부분을 가리키는 포인트
private int size; // 요소 갯수
public MySingleLinkedList() {
this.head = null;
this.tail = null;
this.size = 0;
}
// inner static class
private static class Node<E> {
private E item; // Node에 담을 데이터
private Node<E> next; // 다음 Node 객체를 가르키는 래퍼런스
// 생성자
Node(E item, Node<E> next) {
this.item = item;
this.next = next;
}
}
private Node<E> search(int index) {
// head(처음 위치) 서부터 차례로 index 까지 검색
Node<E> n = head;
for (int i = 0; i < index; i++) {
n = n.next; // next 필드의 값(다음 노드 주소)를 재대입하면서 순차적으로 요소를 탐색
}
return n;
}
public void addFirst(E value) {
// 1. 먼저 가장 앞의 요소를 가져옴
Node<E> first = head;
// 2. 새 노드 생성 (이때 데이터와 next 포인트를 준다)
Node<E> newNode = new Node<>(value, first);
// 3. 요소가 추가되었으니 size를 늘린다
size++;
// 4. 맨앞에 요소가 추가되었으니 head를 업데이트한다
head = newNode;
// 5. 만일 최초로 요소가 add 된 것이면 head와 tail이 가리키는 요소는 같게 된다.
if (first == null) {
tail = newNode;
}
}
public void addLast(E value) {
// 1. 먼저 가장 뒤의 요소를 가져옴
Node<E> last = tail;
// 2. 새 노드 생성 (맨 마지막 요소 추가니까 next 는 null이다)
Node<E> newNode = new Node<>(value, null);
// 3. 요소가 추가되었으니 size를 늘린다
size++;
// 4. 맨뒤에 요소가 추가되었으니 tail를 업데이트한다
tail = newNode;
if (last == null) {
// 5. 만일 최초로 요소가 add 된 것이면 head와 tail이 가리키는 요소는 같게 된다.
head = newNode;
} else {
// 6. 최초 추가가 아니라면 last 변수(추가 되기 전 마지막이었던 요소)에서 추가된 새 노드를 가리키도록 업데이트
last.next = newNode;
}
}
public void add(int index, E value) {
// 1. 인덱스가 0보다 작거나 size 보다 같거나 클 경우 에러
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
// 2. 추가하려는 index가 0이면 addFirst 호출
if (index == 0) {
addFirst(value);
return;
}
// 3. 추가하려는 index가 size - 1와 같으면 addLast 호출
if (index == size - 1) {
addLast(value);
return;
}
// 4. 추가하려는 위치의 이전 노드 얻기
Node<E> prev_node = search(index - 1);
// 5. 추가하려는 위치의 다음 노드 얻기
Node<E> next_node = prev_node.next;
// 6. 새 노드 생성 (바로 다음 노드와 연결)
Node<E> newNode = new Node<>(value, next_node);
// 7. size 증가
size++;
// 8. 이전 노드를 새 노드와 연결
prev_node.next = newNode;
}
public boolean add(E value) {
addLast(value);
return true;
}
@Override
public String toString() {
if (head == null) {
return "[]";
}
Node<E> n = head;
String result = "[";
while (n.next != null) {
result += n.item + ", ";
n = n.next;
}
// n이 마지막일 경우 n.next가 null이니 루프문을 빠져나오게 되서 마지막 노드 삽입 처리를 해주어야 한다.
result += n.item + "]";
return result;
}
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
return search(index).item;
}
public void set(int index, E value) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
// 1. search 메소드를 이용해 교체할 노드를 얻는다.
Node<E> replace_node = search(index);
// 2. 교체할 노드의 요소를 변경한다.
replace_node.item = null;
replace_node.item = value;
}
public E removeFirst() {
// 1. 만약 삭제할 요소가 아무것도 없으면 에러
if (head == null) {
throw new RuntimeException();
}
// 2. 삭제될 첫번째 요소의 데이터를 백업
E returnValue = head.item;
// 3. 두번째 노드를 임시 저장
Node<E> first = head.next;
// 4. 첫번째 노드의 내부 요소를 모두 삭제
head.next = null;
head.item = null;
// 5. head가 다음 노드를 가리키도록 업데이트
head = first;
// 6. 요소가 삭제 되었으니 크기 감소
size--;
// 7. 만일 리스트의 유일한 값을 삭제해서 빈 리스트가 될 경우, tail도 null 처리
if (head == null) {
tail = null;
}
// 8. 마지막으로 삭제된 요소를 반환
return returnValue;
}
public E remove() {
return removeFirst();
}
public E remove(int index) {
// 1. 인덱스가 0보다 작거나 size 보다 크거나 같은 경우 에러 (size와 같을 경우 빈 공간을 가리키는 거니까)
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
// 2. 인덱스가 0이면 removeFirst 메서드 실행하고 리턴
if (index == 0) {
return removeFirst();
}
// 3. 삭제할 위치의 이전 노드 저장
Node<E> prev_node = search(index - 1);
// 4. 삭제할 위치의 노드 저장
Node<E> del_node = prev_node.next;
// 5. 삭제할 위치의 다음 노드 저장
Node<E> next_node = del_node.next;
// 6. 삭제될 첫번째 요소의 데이터를 백업
E returnValue = del_node.item;
// 7. 삭제 노드의 내부 요소를 모두 삭제
del_node.next = null;
del_node.item = null;
// 8. 요소가 삭제 되었으니 크기 감소
size--;
// 9. 이전 노드가 다음 노드를 가리키도록 업데이트
prev_node.next = next_node;
// 10. 마지막으로 삭제된 요소를 반환
return returnValue;
}
public boolean remove(Object value) {
// 1. 만약 삭제할 요소가 아무것도 없으면 에러
if (head == null) {
throw new RuntimeException();
}
// 2. 이전 노드, 삭제 노드, 다음 노드를 저장할 변수 선언
Node<E> prev_node = null;
Node<E> del_node = null;
Node<E> next_node = null;
// 3. 루프 변수 선언
Node<E> i = head;
// 4. 노드의 next를 순회하면서 해당 값을 찾는다.
while (i != null) {
if (Objects.equals(i.item, value)) {
// 노드의 값과 매개변수 값이 같으면 삭제 노드에 요소를 대입하고 break
del_node = i;
break;
}
// Singly Linked List에는 prev 정보가 없기 때문에 이전 노드에도 요소를 일일히 대입하여야 함
prev_node = i;
i = i.next;
}
// 5. 만일 찾은 요소가 없다면 리턴
if (del_node == null) {
return false;
}
// 6. 만약 삭제하려는 노드가 head라면, 첫번째 요소를 삭제하는 것이니 removeFirst()를 사용
if (del_node == head) {
removeFirst();
return true;
}
// 7. 다음 노드에 삭제 노드 next의 요소를 대입
next_node = del_node.next;
// 8. 삭제 요소 데이터 모두 제거
del_node.next = null;
del_node.item = null;
// 9. 요소가 삭제 되었으니 크기 감소
size--;
// 10. 이전 노드가 다음 노드를 참조하도록 업데이트
prev_node.next = next_node;
return true;
}
public E removeLast() {
return remove(size - 1);
}
}
LinkedListMain
public class LinkedListMain
{
public static void main(String[] args) {
MySingleLinkedList<Number> list = new MySingleLinkedList<>();
list.add(3);
list.add(6);
list.add(4);
list.add(3);
list.add(8);
list.add(10);
list.add(11);
System.out.println(list); // [3, 6, 4, 3, 8, 10, 11]
list.add(6, 100);
list.add(0, 101);
list.add(1, 102);
System.out.println(list); // [101, 102, 3, 6, 4, 3, 8, 10, 11, 100]
list.removeFirst();
list.removeFirst();
list.remove(1);
System.out.println(list); // [3, 4, 3, 8, 10, 11, 100]
list.remove(3);
list.remove(3);
System.out.println(list); // [4, 8, 10, 11, 100]
System.out.println(list.get(4)); // 100
list.set(4, 999);
System.out.println(list); // [4, 8, 10, 11, 999]
}
}
알고리즘은 너무 어려워... 내가 수학적 사고가 부족한가 근데 또 코드 풀이를 보면 어려워 보이지는 않는데 알고리즘 적 사고를 하는 게 어렵다... 자바보다는 코테를 준비할 거면 파이썬이 나은 것 같고 배열의 크기 부분이라던지에서도 확실히 너무 차이가 난다... 근데 스프링 공부할 거면 자바도 공부해야 하고 할 거 너무 많아 ㅠㅠㅠㅠ 힝