트리란 한 개 이상의 노드로 이루어진 유한 집합이다.
Stack이나 Queue와 같은 자료 구조의 일종
일렬적인 선형구조(Stack, Queue)가 아닌, 원소들 간 관계를 가지는 비선형 자료구조
상위 원소와 하위 원소의 관계가 있는 계층적 자료구조(DOM, File System, … )
각각 데이터를 담고 있는 원소를 노드(Node) 또는 정점이라 한다.
각 노드는 0개 이상의 자식 노드를 가질 수 있다.
하나의 부모에 여러 자식이 연결되어 있다.
하나의 자식은 둘 이상의 부모를 가질 수 없다.
노드의 개수가 개일 때, 개의 간선을 가지고 있다. 그렇기에 순환 구조가 생기지 않는다.
Binary Tree (이진 트리)
Perfect Binary Tree (포화 이진 트리)
Complete Binary Tree (완전 이진 트리)
Skewed Binary Tree (편향 이진 트리)
이진 트리의 각 노드를 한번씩만 방문하는 체계적인 방법
public class TreeTraverse {
private int nodes;
private int[] arr; // 이진 트리를 표현하기 위한 배열
// { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }
public void setArr(int[] arr) {
this.arr = arr;
this.nodes = arr.length;
}
// 전위 순회 V -> L -> R
// preorder() : System.out.print(V) -> preorder(L) -> preorder(R)
public void traversePreorder(int node) {
if (node < this.nodes && arr[node] != 0) {
System.out.print(arr[node] + ", "); // 방문
this.traversePreorder(node * 2); // 왼쪽 자식(i * 2)을 루트로 다시 preorder 호출
this.traversePreorder(node * 2 + 1); // 오른쪽 자식(i * 2 + 1)을 루트로 다시 preorder 호출
}
}
// 중위 순회 L -> V -> R
// inorder() : preorder(L) -> System.out.print(V) -> preorder(R)
public void traverseInorder(int node) {
if (node < this.nodes && arr[node] != 0) {
this.traverseInorder(node * 2); // 왼쪽 자식(i * 2)을 루트로 다시 preorder 호출
System.out.print(arr[node] + ", "); // 방문
this.traverseInorder(node * 2 + 1); // 오른쪽 자식(i * 2 + 1)을 루트로 다시 preorder 호출
}
}
// 후위 순회 L -> R -> V
// postorder() : preorder(L) -> preorder(R) -> System.out.print(V)
public void traversePostorder(int node) {
if (node < this.nodes && arr[node] != 0) {
this.traversePostorder(node * 2); // 왼쪽 자식(i * 2)을 루트로 다시 preorder 호출
this.traversePostorder(node * 2 + 1); // 오른쪽 자식(i * 2 + 1)을 루트로 다시 preorder 호출
System.out.print(arr[node] + ", "); // 방문
}
}
public static void main(String[] args) {
TreeTraverse tree = new TreeTraverse();
tree.setArr(new int[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });
tree.traversePreorder(1); // 처음 방문점은 root node
System.out.println();
tree.traverseInorder(1);
System.out.println();
tree.traversePostorder(1);
System.out.println();
}
}
메모리 상 저장된 데이터를 전송 가능한 형태로 바꾸는 작업 (XML, YAML, JSON)
직렬화 되어 있는 데이터를 메모리 상에 활용할 수 있는 형태로 바꾸는 작업
package com.example.article.dto;
import com.example.article.entity.ArticleEntity;
import lombok.Data;
@Data
public class ArticleDto {
private Long id;
private String writer;
private String title;
private String content;
public static ArticleDto fromEntity(ArticleEntity entity) {
ArticleDto dto = new ArticleDto();
dto.setId(entity.getId());
dto.setWriter(entity.getWriter());
dto.setTitle(entity.getTitle());
dto.setContent(entity.getContent());
return dto;
}
}
package com.example.article.entity;
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "articles")
public class ArticleEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String writer;
private String title;
private String content;
}
package com.example.article;
import com.example.article.dto.ArticleDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController // @ResponseBody 생략 가능
@RequiredArgsConstructor
public class ArticleController {
private final ArticleService service;
// POST /articles
@PostMapping("/articles")
// RESTful한 API는 행동의 결과로 반영된 자원의 상태를 반환함이 옳다
public ArticleDto create(@RequestBody ArticleDto dto) {
return service.createArticle(dto);
}
// GET /articles
@GetMapping("/articles")
public List<ArticleDto> readAll() {
return service.readArticleAll();
}
// GET /articles/{id}
@GetMapping("/articles/{id}")
public ArticleDto read(@PathVariable("id") Long id) {
return service.readArticle(id);
}
// PUT /articles/{id}
@PutMapping("/articles/{id}")
public ArticleDto update(@PathVariable("id") Long id, @RequestBody ArticleDto dto) {
return service.updateArticle(id, dto);
}
// DELETE /articles/{id}
@DeleteMapping("/articles/{id}")
public void delete(@PathVariable("id") Long id) {
service.deleteArticle(id);
}
}
package com.example.article;
import com.example.article.dto.ArticleDto;
import com.example.article.entity.ArticleEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class ArticleService {
private final ArticleRepository repository;
public ArticleDto createArticle(ArticleDto dto) {
ArticleEntity entity = new ArticleEntity();
entity.setTitle(dto.getTitle());
entity.setContent(dto.getContent());
entity.setWriter(dto.getWriter());
entity = repository.save(entity);
return ArticleDto.fromEntity(entity);
}
public ArticleDto readArticle(Long id) {
Optional<ArticleEntity> optionalArticle = repository.findById(id);
// optional 안에 Article이 들어있으면
if (optionalArticle.isPresent())
// DTO로 전환 후 반환
return ArticleDto.fromEntity(optionalArticle.get());
// 아니면 404
else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
// 위와 반대 순서
// if (optionalArticle.isEmpty())
// throw new ResponseStatusException(HttpStatus.NOT_FOUND);
// return ArticleDto.fromEntity(optionalArticle.get());
}
public List<ArticleDto> readArticleAll() {
List<ArticleDto> articleList = new ArrayList<>();
for (ArticleEntity entity: repository.findAll()) {
articleList.add(ArticleDto.fromEntity(entity));
}
return articleList;
}
public ArticleDto updateArticle(Long id, ArticleDto dto) {
Optional<ArticleEntity> optionalArticle = repository.findById(id);
if (optionalArticle.isPresent()) {
ArticleEntity article = optionalArticle.get();
article.setWriter(dto.getWriter());
article.setTitle(dto.getTitle());
article.setContent(dto.getContent());
return ArticleDto.fromEntity(repository.save(article));
}
else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
public void deleteArticle(Long id) {
if (repository.existsById(id)) {
repository.deleteById(id);
}
else throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
package com.example.article;
import com.example.article.entity.ArticleEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ArticleRepository extends JpaRepository<ArticleEntity, Long> {}
spring:
datasource:
url: jdbc:sqlite:db.sqlite
driver-class-name: org.sqlite.JDBC
jpa:
hibernate:
ddl-auto: create
show-sql: true
database-platform: org.hibernate.community.dialect.SQLiteDialect
# 최초 실행 후 여기부터 아래까지 주석
defer-datasource-initialization: true
sql:
init:
mode: always
출처 : 멋사 5기 백엔드 위키 6팀 식스센스
백엔드 위키 작성
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
접근제어자를 두어야한다. (access = AccessLevel.PROTECTED)
무분별한 접근 막아준다
update, create 등 setter를 지양하는 이유는?
자료변형의 가능성이 있다.
메소드 이용, @builder
어노테이션 이용
JPA
장점
단점
MyBatis
오늘은 어김없이 배운 내용이 쉽지 않았다. 트리 구조는 들어만 봤는데 드디어 접하게 되었지만 코드를 짜라고 하면 절대 못 짤 자신있다. 알고리즘만 해도 공부할게 태산이다.
스프링은 역시나 타자연습시간. 오류없이 실행은 잘되고 코드는 대충 감만 올 뿐 정확하게 이해 못 하는건 당연지사. 진짜 큰일이다 이거야~
스프링을 시작한 후로 야생에 버려진 나는 아기사자반(보충수업 비슷)에 관심이 생겨 이번에 첫 수업을 들어보았다. 일단 멘토님 목소리가 좋다 합격. 19시부터 21시까지 수업하는데 쉬는 시간이 없지만 줌을 키지 않아도 되는게 좋은 것 같다.
수업 내용은 스프링에 관한 멘토님의 꿀팁 몇 가지 얻어가는 정도? 기대한 것에 비해 살짝 아쉬웠지만 그래도 별점 5점중에 3.5점 정도로 괜찮았던 것 같다. 수업 분위기가 무겁지 않아서 그런지 편하게 들을 수 있다는 것이 제일 좋았다. 다음에도 어떤 꿀팁을 건질지도 모르니 한 번 더 들어봐야겠다.