//이진 검색 트리의 노드 구조체
typedef struct node
{
// 노드의 값
int number;
// 왼쪽 자식 노드
struct node *left;
// 오른쪽 자식 노드
struct node *right;
} node;
// 이진 검색 함수 (*tree는 이진 검색 트리를 가리키는 포인터)
bool search(node *tree)
{
// 트리가 비어있는 경우 ‘false’를 반환하고 함수 종료
if (tree == NULL)
{
return false;
}
// 현재 노드의 값이 50보다 크면 왼쪽 노드 검색
else if (50 < tree->number)
{
return search(tree->left);
}
// 현재 노드의 값이 50보다 작으면 오른쪽 노드 검색
else if (50 > tree->number)
{
return search(tree->right);
}
// 위 모든 조건이 만족하지 않으면 노드의 값이 50이므로 ‘true’ 반환
else {
return true;
}
}
해시테이블 : 키와 값이 하나의 쌍을 이루는 자료 구조
해시 함수 : 임의의 데이터를 고정된 길이의 데이터로 매핑하는 함수
해시 : 데이터를 변환하는 기법
해시 함수를 이요한 충돌(Collision) 처리와 검색 시간의 공간 사이의 Trade off
💡 값을 검색할 때 이진 검색 트리가 기본 연결 리스트에 비해 가지는 장점과 단점은 무엇이 있을까요?
- 이진 검색 트리는 O(logn) 만에 검색이 가능하여 검색하는 데에 O(n)이 걸리는 연결리스트에 비해 시간이 적게 걸립니다. 하지만 노드 하나 당 두 개의 노드를 가리켜야 하기 때문에 메모리 사용량이 더 많습니다.
#include <stdio.h>
#include <stdlib.h>
typedef struct stack{
int top;
int capacity;
int* array;
} Stack;
Stack* createStack(int capacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->capacity = capacity;
stack->top = -1;
stack->array = (int *)malloc(stack->capacity*sizeof(int));
return stack;
}
int isFull(Stack* stack) {
return stack->top == stack->capacity-1;
}
int isEmpty(Stack* stack) {
return stack->top == -1;
}
void push(Stack* stack, int item) {
if (isFull(stack))
return;
stack->array[++stack->top] = item;
printf("%d pushed to stack\n", item);
}
int pop(Stack* stack) {
// 이곳을 채워주세요!
if (isEmpty(stack))
return -9999;
return stack->array[stack->top--];
}
int peek(Stack* stack) {
// 이곳을 채워주세요!
if (isEmpty(stack))
return -9999;
return stack->array[stack->top];
}
int main() {
Stack* stack = createStack(100);
printf("%d pop from stack\n", pop(stack));
push(stack, 10);
push(stack, 20);
push(stack, 30);
printf("%d peek from stack\n", peek(stack));
push(stack, 40);
push(stack, 50);
push(stack, 60);
printf("%d pop from stack\n", pop(stack));
printf("%d pop from stack\n", pop(stack));
printf("%d peek from stack\n", peek(stack));
printf("%d pop from stack\n", pop(stack));
printf("%d pop from stack\n", pop(stack));
printf("%d pop from stack\n", pop(stack));
printf("%d pop from stack\n", pop(stack));
printf("%d peek from stack\n", peek(stack));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct stackNode {
int data;
struct stackNode* next;
} StackNode;
StackNode* createStackNode(int data) {
StackNode* node = (StackNode*)malloc(sizeof(StackNode));
node->data = data;
node->next = NULL;
return node;
}
int isEmpty(StackNode* root) {
return !root;
}
void push(StackNode** root, int data) {
// 이 부분을 구현해 주세요!
StackNode* node = createStackNode(data);
node->next = *root;
*root = node;
printf("%d pushed to stack\n", data);
}
int pop(StackNode** root) {
if (isEmpty(*root))
return -9999;
StackNode* temp = *root;
*root = (*root)->next;
int popped = temp->data;
free(temp);
/*
// 메모리 누수 발생
int popped = (*root)->data;
*root = (*root)->next;
*/
return popped;
}
int peek(StackNode** root) {
if (isEmpty(*root))
return -9999;
return (*root)->data;
}
int main() {
StackNode* root = NULL;
push(&root, 10);
push(&root, 20);
push(&root, 30);
push(&root, 40);
printf("%d pop from stack\n", pop(&root));
printf("%d pop from stack\n", pop(&root));
push(&root, 50);
printf("%d peeked from stack\n", peek(&root));
printf("%d pop from stack\n", pop(&root));
printf("%d pop from stack\n", pop(&root));
printf("%d pop from stack\n", pop(&root));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct queue {
int front;
int rear;
int size;
int capacity;
int* array;
} Queue;
Queue* createQueue(int capacity) {
Queue* queue = (Queue *)malloc(sizeof(Queue));
queue->capacity = capacity;
queue->front = 0;
queue->size = 0;
queue->rear = capacity-1; // 왜 이렇게 초기화 했는지 잘 생각해 보세요! : 원형큐 구현을 위해
queue->array = (int *)malloc(sizeof(int)*queue->capacity);
return queue;
}
int isFull(Queue* queue) {
return (queue->size == queue->capacity);
}
int isEmpty(Queue* queue) {
return (queue->size == 0);
}
void enqueue(Queue* queue, int item) {
if (isFull(queue)) {
return;
}
queue->rear = (queue->rear + 1)%queue->capacity;
queue->array[queue->rear] = item;
queue->size = queue->size + 1;
printf("%d enqueued to queue\n", item);
}
int dequeue(Queue* queue) {
if (isEmpty(queue)) {
return -9999;
}
int item = queue->array[queue->front];
queue->front = (queue->front + 1)%queue->capacity;
queue->size = queue->size - 1;
return item;
}
int main() {
Queue* queue = createQueue(1000);
enqueue(queue, 10);
enqueue(queue, 20);
enqueue(queue, 30);
enqueue(queue, 40);
printf("%d dequeued from queue\n\n", dequeue(queue));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node* next;
} Node;
void append(Node* head, int data) {
// 이 부분을 작성해 주세요!
if (head->data == 0){
head->data = data;
return;
}
Node* item = (Node*)malloc(sizeof(Node));
item->data = data;
item->next = NULL;
while(head->next != NULL) {
head = head->next;
}
head->next = item;
}
int getLastNode (Node* head, int k) {
// 이 부분을 작성해 주세요!
int i = 1; //head 사이즈
int cnt = 0;
int data = 0;
Node* temp = head;
while(temp->next != NULL){ // head의 사이즈를 구한다
i++;
temp = temp->next;
}
cnt = i - k;
if(cnt < 0){ // 사이즈를 벗어나면
return -9999;
}
for(int j = 1; j<=cnt; j++){
head = head->next;
}
data = head->data;
return data;
}
void printList(Node* head) {
// 이 부분을 작성해 주세요!
while(1) {
if(head->next == NULL){
printf("%d ", head->data);
break;
}
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main() {
Node* head = (Node*)malloc(sizeof(Node));
for(int i = 1; i<=5; i++)
append(head, i);
printList(head);
for(int i = 5; i>=1; i--)
printf("%dth last node is %d\n", i, getLastNode(head, i));
}
int getLastNode (Node* head, int k) {
Node* fast = head;
Node* slow = head;
int start = 1;
while(fast->next!=NULL) {
fast = fast->next;
start++;
if (start > n) {
slow = slow->next;
}
}
return slow->data;
}
int getLastNode (Node* head, int k) {
Stack* stack = createStack(100);
while(head->next != NULL){
push(stack, head->data);
head = head->next;
}
for(int i =0; i<k-1; i++){
pop(stack);
}
return peek(stack);
}
자료구조라 쓰고 연결리스트라 읽는다..⭐️ 이번주차 핵심은 연결리스트!! 2학년 알고리즘 시간 때 열심히 배웠던 기억이 새록새록 난다. 개념은 쉽지만(?) 구현은 어려운 연결리스트. 포인터때문에 과정을 하나하나 그려보면서 구현해보았다.
이번 미션은 Stack과 Queue의 개념을 정확히 익히기 좋은 문제였다. 다만 2번문제에서 이중포인터 등장에 좀 당황했지만 당황하지 않고 구글링하여 완성된 코드를 보면서 이해하였다..ㅋ 4번 문제는 가장 단순하고 직관적이게 풀었다. 연결 리스트의 크기를 구해서 구한 크기 - k를 해준 값만큼 다시 찾아가 데이터를 얻는 방법을 이용했다. 너무 단순하게 풀어서 기대 안했는데 우수미션으로 선정됐다 ✌🏻 4번 문제를 낸 팀이 별로 없어서 선정된듯하다. 역시 가장 단순한 방법이라고 설명해주셨다. 그 외 알려주신 방법 중 포인터 두개를 활용해 푸는 방법, 스택을 이용해 푸는 방법을 풀어보았다. 포인터 두개를 활용해 푸는 방법은 나의 코드가 모범답안에 비해 너무 장황해서 모범답안을 적어놨다. 초짜는 역시 티가난다 ㅋ
마지막 스터디 😭 언제 6주가 흘렀는지 .. 시간 너무 빠르게 가는거 아니에요 ?! 월요일은 강의를 보고 화요일엔 문제풀고 수요일엔 회의를하고 금요일엔 라이브를 보면서 한 주를 마무리했는데 다음주부턴 그럴 수 없어 아쉽기도 하다. 시원 섭섭한 느낌 ~
이번 cs50 스터디를 통해 많은걸 얻고 가는것 같다. cs에 대한 개념뿐만 아니라 팀미션을 통해 서로의 생각을 공유하고 서로의 코드를 리뷰를 하면서 팀원들에게 나의 코드를 설명해주는 방법과 팀원들의 코드를 해석하는 방법 또한 배울 수 있어 좋았다. 그리고 리드부스터로써 팀원들을 따뜻하게 이끄는 방법 또한 배울 수 있었다. 😊 마지막으로 제일 좋았던건 라이브..! 현업 개발자분들이 문제를 풀이해주시고 질문에 답해주시면서 유익한 정보를 많이 얻을 수 있었다.
사실 리드부스터로써 우여곡절(?)도 많았지만 끝까지 함께 해준 팀원들 덕분에 훈훈하게 마무리 할 수 있었다. 팀원 중 한 분은 이번 스터디를 통해 컴공을 복전하실거라고 하셨다.. 👍🏻 cs50스터디 당연히 코딩입문자에게도 추천하지만 나같이 기초가 부족한 전공자에게는 더더욱 추천한다!
3기를 고민하시는 분들 당장 신청하세요 !! 😁