일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- batflat
- git merge
- 라즈베리 파이
- 서버 백업
- IRC 서버
- 웹 서버
- 라즈베리
- 라즈베리파이
- 웹 유저
- 커맨드
- 리눅스 커맨드
- 우분투 설치
- github
- 리눅스 사용자
- 서버
- 리눅스
- 라즈베리파이 실습
- 명령어
- date
- 웹사이트
- java
- Linux
- 블로그 만들기
- github command
- 웹 만들기
- 컴활 1급
- windows10
- 컴퓨터 활용능력
- git branch
- OverTheWire
- Today
- Total
돌공공돌
22-04-15 (데이터 구조 중간시험) D-3 본문
데이터 구조 – 중간고사 (7주차 까지)
1. Algorithm Efficieny
O(n) , O(logn) -> 어떤 프로그램에 대해서 BIG-O notation 판단 할 수 있는 정도
2. Stack
1) Array를 이용한 방법 & Linked List를 이용한 방법 -> 모두 구현할 수 있는 수준 (스택짜기)
array를 이용한 stack 구현
/*
array를 이용한 stack 을 구현하려고 한다.
stack에 필요한게 뭐지?
1. 일단 array
2. top
memberfunction
-constructor
-push
-pop
-stack_full
-stack_empty
*/
#include <iostream>
using namespace std;
#define SIZE 100
class mystack {
private:
int s[SIZE];
int top;
public:
mystack();
void push(int n);
int pop();
bool stack_full();
bool stack_empty();
};
mystack::mystack(){
top = 0;
}
void mystack::push(int n){
if (stack_full()){
cout<<"This stack is full" << endl;
return ;
}
s[top] = n;
top ++;
}
int mystack::pop(){
if(stack_empty()){
cout<<"This stack is empty : ";
return 0;
}
top--;
return s[top];
}
bool mystack::stack_full(){
if (SIZE < = top)
return true;
else
return false;
}
bool mystack::stack_empty(){
if (top == 0 )
return true;
else
return false;
}
int main()
{
mystack s1;
int list[5] = { 32, 123, 27, 131, 242 }, i, x;
for (i = 0; i < 5; i++ )
s1.push( list[i] );
while ( ! s1.stack_empty( ) )
{
x = s1.pop( );
cout << x << endl ;
}
return 0;
}
linked list 를 이용한 stack 구현
#include <iostream>
using namespace std;
//node --> self-referential class type
//data는 일단 가장 익숙한 이름과 점수로 가자
class node {
public:
string name;
double score;
node *link;
void set_data(string s , double n); // 이건 기본적으로 당연히 들어가는 거니까 외워두자
};
// 이걸 해줘야 접근 가능하겠구나..
void node::set_data(string s,double n){
name = s;
score = n;
}
class ll_stack {
// top이 한 노드를 가리킨다.
node *top;
public:
ll_stack(); // constructor
void push(node d1);
node pop();
bool stack_empty();
};
//constructor
ll_stack::ll_stack(){
top = NULL;
}
//push 해주는 거 head에 원소 추가 하는 거랑 동일?
/*
node * p —> 노드를 데이터 타입으로 하는 변수의 주소를 저장한다.
p = new node —> 한 개 공간 allocation 해주고, 그 위치를 return p 에는 주소가 저장되어있다. 어쨌든 노드의
(*p) = t; —> 일반 노드의 데이터가 p가 가리키는 노드 값에 저장된다.
p->link = head; // p는 주소를 저장하는 변수인데, 어떻게 link에 접근이 가능하죠? —> 잠시만 (*p).link 와 p->link가 같은 말이다 따라서 이 문장은 말이 된다. head가 가리키고 있는 노드 에대한 주소를 p->link가 받아온다.
head = p ; head도 노드 포인터 변수이고, p도 포인터 변수 이기 때문이다.
*/
//linked list 개념을 이용한 push
void ll_stack::push(node d1){
node *t; //노드를 데이터 타입으로 하는 변수의 주소를 저장하는 포인터 변수 t
t = new node; // t를 위한 공간을 allocation 해준다. 동적인 할당 t = new node가 없으면 안되는 이유, initialization 이 필요하기 때문이다. 왜냐하면 t 에 통째로 어떤 주소값이 들어오지 않기 때문이다. 데이터만 들어온다.
(*t)=d1;
(*t).link = top;
top = t;
// delete t? 기계적으로 동적인 할당을 해주면 당연히 안된다...그럼 push 되는게 없는걸? delete 는 pop에서 해주는 것
}
node ll_stack::pop(){
node data;
node *z;
//z = new node; //이게 없다..! 왜? 있어도 되고 없어도 된다. --> push되어있는 top에서 데이터를 가져오는 것이기 때문에,,,new로 새롭게 노드 만들어줄 필요없다 --> 있어도 되고, 없어도 된다.
//empty check if true return NULL
if (stack_empty()){
cout<<"This stack is empty";
return data;
}
//1) z라는 노드포인터 변수에 top이 가리키는 주소를 넣는다. delete 해주기 위해서,
z = top;
//2) data라는 노드에 top의 데이터 들을 저장한다. return 하기 위해서
data = (*top);
//3) top이 다음 노드의 주소를 가리키게 한다. 링크 조정
top = top->link;
//4) 데이터 delete
delete z;
return data;
}
bool ll_stack::stack_empty(){
if(top == NULL)
return true;
else
return false;
}
int main(){
ll_stack a;
node tmp;
tmp.set_data("Lee",22.2);
a.push(tmp);
tmp.set_data("Kim", 33.3);
a.push(tmp);
tmp.set_data("Park",55.2);
a.push(tmp);
tmp.set_data("Choi", 96.3);
a.push(tmp);
tmp = a.pop();
cout << tmp.name<<":"<<tmp.score<<"\n";
tmp = a.pop();
cout<<tmp.name<<":"<<tmp.score<<"\n";
}
2) 스택을 활용한 연산 구현 (연산 짜기) -> array를 사용하여 push와 pop 어떻게 일어나는지 확인을 하라.
3. queues
1) Array를 사용한 구현 --> 구조 , 구현할 수 있는 수준
2) Circular queue --> 어떻게 하는지에 대한 구체적인 구현 내용
Circular queue를 사용하는 이유는 한정된 array크기 rear == array size이면 delete하더라도 , 비어있는 공간을 못 쓰게 된다.
그래서 % 연산자를 이용하여 , circular queue를 완성한다. 이때 문제가 생긴다.
https://lktprogrammer.tistory.com/59
03 원형 큐 (Circular Queue) 자료 구조
원형큐 (Circular Queue) 원형 큐는 선형 큐의 문제점을 보완하기 위한 자료구조입니다. 앞선 포스팅에서 선형큐의 문제점은 rear이 가르키는 포인터가 배열의 마지막 인덱스를 가르키고 있을 때 앞
lktprogrammer.tistory.com
3) full_check 논리--> full, empty 혼동 시키는 문제, 이거 어떻게 구현할 수 있는지에 대해 복습
if(rear == front) 일 경우 full과 empty의 구별이 모호하기 때문에
full_check하는 방법은 마지막 남은 한 개의 빈공간을 사용하지 않는 것을 전제로 하여
(rear+1)%Q_size == front 이런 식으로 한다 --> 이것의 뜻은 하나 증가 했을 때 만난다면 full
array를 이용한 queue 구현
/*Queues 를 array 로 구현해 보자
Queue에 필요한 연산
initialization : front (원소를 읽을 곳) , rear (다음 원소를 넣을 곳)
insert : queue 에 한 개 원소를 저장 (rear 위치에 원소를 넣고, rear++ , 사전 full test)
delete : queue 로부터 한 개 원소를 취함 (front 위치에서 원소를 가져오고 front++ , 사전 empty test)
Full test : Circular queue 해결 방안
Empty test :
rear에서 insert, front에서 delete
*/
#include <iostream>
using namespace std;
#define SIZE 100
// 모든 data type 에 적용할 수 있도록 하는 queue를 만들기 위해, 대표적으로 이름과 ,score 를 저장하는, element를 생성하자
class element{
public:
string sname;
double score;
void set_data(string s, double d);
};
//setdata 함수 자동적으로 나와야 한다...
void element::set_data(string s, double d){
sname = s;
score = d;
}
class array_queue{
private:
element q[SIZE];
int front , rear;
public:
array_queue(); // constructor
void insert_q(element e); // insert element in rear
element delete_q(); // delete element in front
bool queue_full(); // queue가 full인지 판단 , 판단기준 (rear+1)%SIZE == front
bool queue_empty(); // queue가 empty 인지 판단, 판단기준 rear == front
};
array_queue::array_queue(){
rear = 0 ;
front = 0;
}
void array_queue::insert_q(element e){
if(!(queue_full())){
q[rear] = e;
rear = (rear+1)%SIZE;
}
else
cout<<"The Queue is full"<<endl;
}
element array_queue::delete_q(){
element tmp;
if(!(queue_empty())){
tmp = q[front];
front = (front+1)%SIZE; // 단순히 front ++을 하면 안 된다. 순환해야 한다
return tmp;
}
else{
cout<<"The Queue is empty: ";
return q[front];
}
}
bool array_queue::queue_full(){
if(front == (rear+1)%SIZE)
return true;
else
return false;
}
bool array_queue::queue_empty(){
if(front == rear)
return true;
else
return false;
}
int main() {
array_queue a;
element tmp;
tmp.set_data("KIM",49.4);
a.insert_q(tmp);
tmp.set_data("Lee", 99.3);
a.insert_q(tmp);
tmp.set_data("Park", 34.4);
a.insert_q(tmp);
while(!a.queue_empty()){
tmp = a.delete_q();
cout << tmp.sname<<":"<<tmp.score<<"\n"; //sname과 score가 public인 이유
}
return 0;
}
linked list 를 이용한 queue 구현
//linked list 개념을 이용한 queue를 구현해보자
// 일단 기본적으로 insert, delete가 rear 와 front에서 일어나도록 해줘야한다.
// head 에서 원소의 추가 삭제가 일어나는게 용이하다.
// tail 에서 원소의 추가가 용이하지만 삭제는 어려움
// 따라서 head --> front (삭제가 일어남) , tail은 rear(원소 추가) 로 한다.
// 원소는 당연히 node 가 되겠지.
#include <iostream>
using namespace std;
class node {
public:
string name;
double score;
node *link;
void set_data(string n , double s );
};
void node:: set_data(string n, double s){
name = n;
score = s;
}
class llqueue {
private:
node *front;
node *rear;
public:
llqueue();
void insert_q(node n);
node delete_q();
// bool full_check(); linked list 는 dynamic memory 이므로 , full_check할 필요가 없다
bool empty_check();
};
llqueue::llqueue(){
front = NULL;
rear = NULL;
}
void llqueue::insert_q(node n){
node *t;
t = new node;
(*t) = n;
// 이 밑으로 순서 중요하다.
t->link = NULL;
if(rear != NULL)
rear->link = t;
else
front = t; //rear 가 가리키고 있는 node가 가리키는 값,, ㅋㅋ 그림으로 보면 이해가 쉬운데,글은 좀 어렵다.
rear = t;
}
node llqueue::delete_q(){
node tmp;
node *t;
/* if(empty_check()){
cout << "The queue is empty" << "\n";
return tmp;
}
*/
t = front;
tmp = (*front);
front = front->link;
delete t;
if (front == NULL)
rear = NULL;
return tmp;
}
bool llqueue::empty_check(){
if (rear == NULL)
return true;
else
return false;
}
int main() {
llqueue a;
node tmp;
tmp.set_data("KIM",49.4);
a.insert_q(tmp);
tmp.set_data("Lee", 99.3);
a.insert_q(tmp);
tmp.set_data("Park", 34.4);
a.insert_q(tmp);
while(!a.empty_check()){
tmp = a.delete_q();
cout << tmp.name<<":"<<tmp.score<<"\n"; //sname과 score가 public인 이유
}
return 0;
}
//그냥 linked list 랑 코드가 아예 똑같다.
// add to tail 과 delete from head 으로, rear에 넣고, front에서 빼기가 가능하다.
4. Recursion
1) base , n에 대한 solution --> (n+1 or n-1), n --> 다른 데이터 스트럭쳐에도 사용할 수 있을 정도로 숙달하면 좋겠다. 하나 적은 것에 대해 solution 이 생성 될 수 있다면 거기에 대해 어떤 추가적인 작업이 있어야, n 에 대한 수식을 도출할 수 있다.
5. C++ 언어
1) 기초 문법 : 기본 입출력
2) class 사용한 구현 --> ADT
3) String Class
6. Expression 표현
a+b : infix , prefix, postfix --> 이것들이 무엇이며 우리가 써왔던 infix를 prefix나 postfix로 바꾸는 방법을 이해하라 && stack을 사용해서 infix를 postfix로 바꾸는 알고리즘
7. Stack 응용
infix -> postfix
기타 실습 문제 --> stack을 자유롭게 쓸 수 있는 방법을 알아둬라
8. Linked Lists
자기 자신과 같은 데이터 타입을 가리킬수 있는 포인터 타입을 link로 사용해서, 다음 node를 head와 tail 첫 노드를 가리키는 포인터 만으로도 다룰 수 있다면 p부터 정해진 문제를 해결 할 수 있는 , 원소를 추가한다거나 판단한다거나 할 수 있을 정도로 공부를 해 둬라
9. list node 를 위한 class 선언
노드의 형태가 head , tail로 이렇게 일반적 이긴 하지만, 문제에 따라 유연하게 해석 할 수 있어야 한다.
이러한 구조가 아닌 pointer 하나만 사용해서도 할 수 있다. --> 이거는 염두해두고 주어진 문제에 중심을 두고 해결
//계속 반복 연습이 필요하다.
/*add_to_head() //head위치에 한 개의 원소 추가
add_to_tail() // tail 위치에 한 개의 원소 추가
delete_from_head()// head 위치의 한 개 원소 삭제
num_nodes() //현재의 Node 수 확인 --> traversal
list_empty() // node비어있는지 확인
inver() // 역순으로 재배열 하라
list_equal() // 두 리스트가 같은지 판단
score_sum() // 전체 스코어의 합 구하기
get_score(string name)
remove_a_node(string name) //특정 이름을 같는 노드 삭제
*/
#include <iostream>
using namespace std;
//일단 여태껏 하는 것 처럼 이름과 점수를 저장하는 node class를 만들어주자.
class node {
public:
string name;
double score;
node *link;
void set_data(string n , double s);
};
void node::set_data(string n, double s){
name = n;
score = s;
}
//linked list class
class my_list{
node *head, *tail;
public:
my_list();
void add_to_head(node n); //head위치에 원소 추가
void add_to_tail(node n); //tail위치에 원소 추가
node delete_from_head(); //head위치에 원소 삭제
int num_nodes(); //현재의 node수 확인
bool list_empty(); // list가 비어있는지 확인
double score_sum(); //현재 list 모든 node의 score 합 return
double get_score(string t_name); // 't_name'으로 저이진 name의 score return
int remove_a_node(string t_name); //'t_name'에 해당하는 node 삭제, 성공하면 1 return, 해당 노드가 존재하지 않으면 0 return
void invert(); // 역순으로 재배열 하라
friend bool list_equal(my_list l1 , my_list l2); // 두 리스트가 같은지 판단
};
bool is_equal(node *p1 , node *p2);
bool equal_data(node t1 , node t2);
//constructor
my_list::my_list(){
head = NULL;
tail = NULL;
}
// linked list 를 이용한 stack 의 원소 추가에 이용됨
void my_list::add_to_head(node n){
node *p;
p = new node;
(*p) = n;
p->link = head;
head =p;
if(tail == NULL)
tail = p;
}
// linked list 를 이용한 queue 원소 추가에 이용됨
void my_list::add_to_tail(node n){
node *p;
p = new node;
(*p) = n;
p->link = NULL;
if (tail == NULL)
head= p;
else
tail->link = p; // 이전 테일이 추가한 테일에 연결 하도록 한다.
tail = p;
}
// linked list를 이용한 stack 과 queue에 모두 이용됨
node my_list::delete_from_head(){
node tmp;
node *t;
tmp = (*head); // tmp에 head데이터 넣기
t = head; // t에 head 연결 시키기
head = head->link; // head 에 head 다음거 연결 시키기
delete t; //t delete
if(head == NULL) // 삭제 후 emmpty 가 되면 tail 값도 조정
tail = NULL;
return tmp; //tmp (head) 값 return
}
//traversal 개념
int my_list::num_nodes(){
node *t;
int count=0;
t = head;
if(!list_empty())
while (t!=NULL){
t = t->link;
count++;
}
return count;
}
bool my_list::list_empty(){
if (head == NULL)
return true;
else
return false;
}
double my_list::score_sum(){
double score =0;
node *t;
t = head;
while(t != NULL){ //조건이 tail 이면 tail이 되는 순간 것은 빼고 연산하기 때문에 tail노드가 빠진 결과가 나오게 된다.
score += t->score; //밑에거랑 순서 중요!
t = t->link;
}
return score;
}
double my_list::get_score(string t_name){
node *t;
t = head;
while(t != NULL){
t = t->link;
if(t->name == t_name)
break;
}
return t->score;
}
//성공하면 1 return 해당노드가 존재하지 않으면 0 return
//알고리즘 , t_name이랑 같은 name을 갖는 노드 한 개 전꺼를 찾고, 그 link를 찾은 노드 다음 거랑 연결시킨다.
//그리고 delete할 때는 delete_From_head할 때랑 똑같이 하면 될 듯
int my_list::remove_a_node(string t_name){
int state = 0;
node *t , *tmp;
for( t= head ; t!= NULL ; t=t->link){
if(t_name == t->link->name){
tmp = t->link;
t -> link = tmp->link;
delete tmp;
state =1;
break;
}
}
return state;
}
//역순으로 재배열 와,, 이거 진짜 어떻게 하는거지?!
void my_list::invert(){
node *newhead , *oldhead, *tmp;
newhead = NULL;
oldhead = head;
while(oldhead != NULL){
tmp = newhead;
newhead = oldhead;
oldhead = oldhead -> link;
newhead ->link =tmp;
}
tail = head;
head= newhead;
}
//list equal
//recursive 한 algorithm
bool list_equal(my_list a, my_list b){
return is_equal(a.head , b.head);
}
bool is_equal(node *p1 , node *p2){
if (p1==NULL && p2 == NULL)
return true;
if(p1 == NULL || p2 == NULL)
return false;
if(equal_data(*p1,*p2))
return(is_equal(p1->link, p2->link));
else
return false;
}
bool equal_data(node t1 , node t2){
if(t1.name != t2.name)
return false;
if(t1.score != t2.score)
return true;
return true;
}
/*
int main(int argc, const char * argv[]) {
my_list a,b; node tmp;
tmp.set_data("Kim", 83.5);
a.add_to_head(tmp);
tmp.set_data("Lee", 78.2);
a.add_to_head(tmp);
tmp.set_data("Park", 91.3);
a.add_to_head(tmp);
tmp.set_data("Choi", 85.1);
a.add_to_head(tmp);
tmp.set_data("Choi", 85.1);
b.add_to_head(tmp);
tmp.set_data("Park", 91.3);
b.add_to_head(tmp);
tmp.set_data("Lee", 78.2);
b.add_to_head(tmp);
tmp.set_data("Kim", 83.5);
b.add_to_head(tmp);
tmp = a.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = a.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = a.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = a.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
b.invert();
tmp = b.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = b.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = b.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
tmp = b.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
b.invert();
if (list_equal(a, b) )
cout << "Yes, the two lists are identical. \n";
else
cout << "No, They are not identical.\n";
tmp = b.delete_from_head();
cout << tmp.name << " : " << tmp.score << "\n";
return 0;
}
*/
int main( )
{
my_list a;
node tmp;
tmp.set_data("Kim", 83.5);
a.add_to_head(tmp);
tmp.set_data("Lee", 78.2);
a.add_to_head(tmp); // head 위치로 2개의 원소 추가
cout << a.num_nodes() << " : " << a.score_sum() << "\n"; // 1단계 점검
tmp.set_data("Park", 91.3);
a.add_to_tail(tmp); // tail 위치로 1개의 원소 추가
cout << a.num_nodes() << " : " << a.score_sum() << "\n"; //2단계 점검
tmp = a.delete_from_head();
cout << tmp.name << " is deleted.\n"; // 3단계 점검
tmp.set_data("Choi", 85.1);
a.add_to_tail(tmp);
tmp.set_data("Ryu", 94.3);
a.add_to_head(tmp); // 2개의 원소 추가
cout << a.num_nodes()<<" : " << a.score_sum() << "\n";
cout << "Park’s score : " << a.get_score("Park")<< "\n"; // 4단계 점검
if ( a.remove_a_node("Kim") == 1)
cout << "Kim is deleted from the list. \n"; // 5단계 점검
cout << a.num_nodes()<< " : " << a.score_sum() << "\n"; // 최종 점검
return 0;
}
10) linked list의 추가 member function
1. double score_sum() :현재 list 모든 node의 score 합 return
2. double get_scroe (string t_name) : t_name으로 주어진 name의 score return
3. remove_a_node(string_t_name) : t_name에 해당하는 node 삭제, 성공하면 1 return , 해당 노드가 존재하지 않으면 0 return
11) linked list 연산 : 교수님이 바라는 수준 --> 어떤 연산이 와도, 재량껏 만들어 낼 수 있을 만한 수준 , traversal 누락없이 중복없이 전체를 훑어서 판단 하는 연산, 임의의 위치에 원소를 넣든지 지우든지 하는 것이 연산의 주 내용
12) linked list를 이용한 stack의 구현 --> linked list 원소 추가 삭제 개념과 거의 같다. 자유롭게 구현 가능한 수준
13) linked list를 이용한 queue의 구현. --> linked list 원소 추가 삭제가 비슷하다. 끝에서 동작한다.
앞에 첫 노드를 가리키는 포인터 하나로 linked list 유지할 수 있다. 이것도 참고해서 알아둬라
14) Trees : 노드와 노드의 종속 관계 : 용어 정리 --> 달달 외울 필요가 없지만 시험에 용어가 나왔을 때 그것을 이해할 수 있는 정도는 되어라. 임의의 degree의 tree를 만들면 branch(공간)를 유지하는게 어렵기 때문에 binary tree를 이용한다. binary tree 에 대해 집중적으로 공부
15) binary tree : 어떤 노드와의 관계에서 왼쪽과 오른쪽 최대 2개의 subtree , 구조적인 이해나 이것을 이용한 연산을 할 수 있어야 한다. binary tree에 대한 구조적 정의 lemma-2 어떤 binary tree 에서 degree가 0인 node(leaf)의 수는 degree 가 2인 Node 수 보다 1개 많다.
n0 = n2+1 --> 구조적으로 이해해둬라
16) binary tree traversal : 모든 node에 대하여 중복이나 누럭없이 일정 순서로 특정 작업을 수행
inorder traversal : left – node 처리 – right
preorder traversal : node처리 – left – right
postorder traversal : left – right -node 처리
처리 과정 원리 이해
17) Traversal algorithm – recursive 하게 생각하면 됨
주어진 tree 가 null 이면 그대로 return
null 이 아니면 , 다음을 수행
- left subtree를 inorder traversal 한다.
- root의 data를 처리한다.
- right subtree 를 inorder traversal한다.
18) Expression tree : tree 를 이용해서, preorder --> prefix, postorder -->postfix
19) my_tree class 정의 : class 모양이 항상 그렇게 되어야만 하는 것은 아니다.
tree memberfunction 구현 할 수 있어야 한다.
20) Binary tree 추가주제 : selection trees , 이미 sorting된 list 무더기, 이것을 하나로 합쳐서 , sorting 하라. (winner tree, loser tree 특징을 이해하라) , counting binary trees --> equivalent한 2개 문제 유형 , 공식을 이용해서 풀어라
여기서 언급된 내용이 시험 범위
8주차 목요일 강의는 동영상 강의로 대체
이후 수업의 형태는 공지 유의
'2022-1' 카테고리의 다른 글
22-04-16 (0) | 2022.04.16 |
---|---|
22-04-15 (데이터 구조) (0) | 2022.04.15 |
22-04-15 (데구-통계 D-4 , 선대-물실 D-6 ,데과 D-7) (0) | 2022.04.15 |
22-04-14 (데구, 통계 D-4) (0) | 2022.04.14 |
22-04-13 (0) | 2022.04.13 |