package main
import "fmt"
type Node struct {
next *Node
val int
}
//결합성 높이고 의존성 줄여~
//관련있는 애들 묶어주자. 하나의 struct으로 묶기
//1. 새 struct만듦
type LinkedList struct {
//루트를 포인트형으로 가지고 있음
root *Node
tail *Node
}
//2. 메서드 3개 추가함 add remove printNode
//LinkedList가 가지고 있는기능, 메서드
func (l *LinkedList) AddNode(val int) {
if l.root ==nil {
//없는 상태면
//루트는, 새로만든 노드의 메모리 주소를 포인트 형태로 갖고 있고
l.root = &Node{val:val}
//테일은 자료가 없으니까 루트랑 똑같음
l.tail= l.root
return
}
//꼬리 다음을 새로운 노드 만들어서 붙이면 됨
l.tail.next = &Node{val:val}
l.tail= l.tail.next
}
func (l *LinkedList) RemoveNode(node *Node ) {
if node == l.root {
l.root = l.root.next
node.next = nil
return
}
prev := l.root
for prev.next != node {
prev = prev.next
}
if node== l.tail {
prev.next = nil
l.tail = prev
} else {
prev.next= prev.next.next
}
node.next = nil
}
func (l *LinkedList) PrintNodes() {
//그다음 노드가 없을때까지 전진
node := l.root
for node.next != nil {
fmt.Printf("%d -> ",node.val)
node = node.next
}
fmt.Printf("%d\n",node.val)
}
func main() {
//이안에 root와 tail 포함되어있어서 따로 만들 필요 없음
list := &LinkedList{}
list.AddNode(0)
// var root *Node
// var tail *Node
// //노드의 주소를 root로 가지고 있음
// root = &Node{val: 0}
// //맨처음꺼 하나만 있을 때는 tail은 root와 같음
// tail= root
for i:=1; i<10; i++ {
// tail= AddNode(tail,i)
list.AddNode(i)
}
list.PrintNodes()
list.RemoveNode(list.root.next)
list.PrintNodes()
list.RemoveNode(list.root)
list.PrintNodes()
list.RemoveNode(list.tail)
list.PrintNodes()
fmt.Printf("tail:%d\n", list.tail.val)
}
// //노드 추가하는 거를 함수로 만들게요 //새로 추가된 노드로 반환값있어야함
// func AddNode(tail *Node, val int) *Node {
// // var tail *Node
// // tail = root
// // for tail.next != nil {
// // tail = tail.next
// // }
// //맨 마지막에 새 노드 추가
// node := &Node{val: val}
// tail.next = node
// return node
// }
// func RemoveNode(node *Node,root *Node, tail *Node ) (*Node, *Node) {
// //내가 지우고자 하는 노드가 맨 앞인 경우
// if node == root {
// //새로운 루트는 기존 루트의 다음이 됨
// root = root.next
// if root == nil {
// tail= nil
// }
// return root, tail
// }
// //이전 노드 다음이 현재 지우고자 하는 노드가 아니면
// //이전을 이전다음으로 보내. 맞게 되면 for문 빠져나가
// prev := root
// for prev.next != node {
// prev = prev.next
// }
// if node== tail {
// prev.next = nil
// tail = prev
// } else {
// prev.next= prev.next.next
// }
// return root, tail
// }
// func PrintNodes(root *Node) {
// //그다음 노드가 없을때까지 전진
// node := root
// for node.next != nil {
// fmt.Printf("%d -> ",node.val)
// node = node.next
// }
// fmt.Printf("%d\n",node.val)
// }
Golang
- linkedlist struct로 코드정리 (터커강의 코드) 2021.12.08
- 동적배열 slice개념 (go,append,슬라이스,배열) 2021.12.07
- 포인터 개념(쓰는 이유), 메모리 주소 복사 , 내부 값 호출과 차이점 2021.12.01
linkedlist struct로 코드정리 (터커강의 코드)
동적배열 slice개념 (go,append,슬라이스,배열)
동적배열 종류
c++ STL에 vector / java에는 array list/ c#에는 list / golang에는 slice
동적배열은? <--------------------------> 정적배열(fixed size array 길이 정해진 배열 [10]int)
[]int
길이 변하는 배열
실제 고정 길이의 배열이 따로 있고 그 고정 길이 배열을 가르키고, 포인트하고 있다!!
배열의 길이가 늘어나면 새로운 더 긴 배열을 만든 다음에 거기로 모든 값을 복사시키고 그 배열로 포인트 바꿈
"동적 배열은 실제 배열을 포인트하고 있다."
동적배열선언 만드는 여러 방법들
var a [] int
a:=[]int{초기값}
a:=make([]int,3)
a:=make([ ]int, length, capacity)
length 길이
내가 쓰고 있는 길이
capacity 확보해놓은 공간
(동적배열, 값을 추가할 때 배열 늘리는데 2배씩 확보해놓음 그래서 길이와 cap다를 수 있음)
항목 추가 명령어 append
a:= []int {}
a= append(a,1)
a에 다시 대입
슬라이스 = append(슬라이스,항목)
a[start Index : End Index]
(start ~ end] 마지막은 포함안됨
a[10]int{1,2,3,4,5,6,7,8,9,10}
a[4:6]
a[시작인덱스 5번째 : 6번째]
즉 5번째~6번째까지 슬라이스 의미
a[4: ]
5번째부터~ 끝까지
a[ :4]
처음부터 ~4번째까지
슬라이스는 원래 배열이 있고 그 배열을 가르키는 포인터
슬라이스는 잘라내는 게 아니라 그 일부분을 가르키는 배열!
//추가된 값이 원래길이,확보된 공간 벗어나게 되면
새 메모리 만들어서 거기에 복사됨. 그럼 메모리 주소 바뀜!
코드로 보기
package main
import "fmt"
func main() {
//////////////////////////////////len cap 메모리를 새로 확보해야돼서 주소도 달라짐 새로운 메모리에 담아서
// a:= []int{1,2}
// b:= append(a,3)
// fmt.Printf("%p %p\n",a,b)
// for i := 0; i<len(a); i++{
// fmt.Printf("%d,",a[i])
// }
// fmt.Println()
// for i := 0; i<len(b); i++{
// fmt.Printf("%d,",b[i])
// }
// fmt.Println()
// fmt.Println(cap(a)," ", cap(b))
///////make로 넣기//메모리 같아서 b값 바꾸니까 a도 바뀜
// a:= make([]int, 2,4)
// a[0]=1
// a[1]=2
// b:= append(a,3)
// fmt.Printf("%p %p\n",a,b)
// fmt.Println(a)
// fmt.Println(b)
// b[0]=4
// b[1]=5
// fmt.Println(a)
// fmt.Println(b)
//////처음부터 아예 공간을 다르게 확보하게 싶다면
// a:= []int{1,2}
//
// a := make([]int, 2, 4)
// a[0] = 1
// a[1] = 2
// //슬라이스 새로 만듦
// b := make([]int, len(a))
// for i := 0; i < len(a); i++ {
// b[i] = a[i]
// }
// b = append(b, 3)
// fmt.Printf("%p %p\n",a,b)
}
3가지 경우임
1. 값넘쳐서 새 메모리에 담아짐
2. 값안넘쳐서 메모리 a랑 b같음 b변경될때 그대로인 메모리안에서 바뀌어서 a도 바뀜
3. 아예 슬라이스 새로 만들어서 공간 따로 확보함
//배열 뒤에서 하나씩 지우기
package main
import "fmt"
//뒤에 하나씩 지워나가는 함수//배열 반환,int 맨뒤에 값도 반환
func RemoveBack(a []int) ([]int, int){
//처음부터 a배열길이에서 1뺀것, 즉 맨뒤에를 하나 없앤다
return a[ :len(a)-1], a[len(a)-1]
}
func main() {
a:=[]int{1,2,3,4,5,6,7,8,9,10}
for i :=0; i<5; i++{
var lastlostone int
a, lastlostone= RemoveBack(a)
fmt.Printf("%d,",lastlostone)
}
fmt.Println()
fmt.Println(a)
}
'웹 공부' 카테고리의 다른 글
시퀄라이즈 테이블 코드 자동 생성하는 법(mysql,database,sequelize) (0) | 2022.03.10 |
---|---|
rollbackFailedOptional 문제 (0) | 2022.02.28 |
printf와 println 차이 (0) | 2021.12.07 |
%d , %p의 의미는? (C 언어 변환문자 의미 자료형) (0) | 2021.12.07 |
aws 비용청구 환불은 받았지만 찜찜..(탄력적 IP,사용하지 않는 인스턴스) (3) | 2021.12.05 |
포인터 개념(쓰는 이유), 메모리 주소 복사 , 내부 값 호출과 차이점
package main
import "fmt"
func main() {
//a는 int 형 이라 선언
var a int
//p는 int형 포인트
var p *int
//p에 a 주소 대입, p의 값은 a의 주소를 가르키고 있다
p = &a
//a는 3으로 대입
a=3
//3
fmt.Println(a)
//0xc000100028 메모리의 주소 나옴
fmt.Println(p)
//포인터가 가르키는 값 3(주소가 가르키는 값)
fmt.Println(*p)
}
포인터 왜 쓰냐
원래 a출력했을 때
x++로 해도
값만 복사됐지 a와 b는 다른거라서 1추가 안되고 여전히 1이었음
x는 괄호 밖에서 역할 못하고
포인터 쓰면
package main
import "fmt"
func main() {
//포인터가 왜 사용되는지 보자`~~~~`
var a int
a=1
//포인터형 *x으로 해서 a의 주소값으로 해야함
Increase(&a)
fmt.Println(a)
}
func Increase(x *int) {
//x가 가지고 있는 값은 메모리 주소인데
//그 메모리가 가르키는 주소의 값은 = 메모리가 가르키는 주소의 (원래)값 + 1
*x=*x+1
//얘는 아까 x++와 같은 거라 볼 수 있쥐, 그때 포인터로 안하면 a에서 값만 복사돼서 x++여도 x는 함수 안이라서 a가 늘어나진 않았어
}
이거 사용해서
structure로 만든 거 보기
함수는 값이 복사돼서 쓰이기만 하지
안에 있는 s는 다 다른거임 그래서 결과도 넣은 거 안나오고
수학,a라고 나옴
package main
import "fmt"
type Student struct {
name string
age int
grade string
class string
}
func (s Student) PrintSungjuk(){
fmt.Println(s.class,s.grade)
}
func (s Student) InputSungjuk(class string, grade string){
s.class = class
s.grade =grade
}
func main(){
var s Student= Student{name: "t",age:23, class: "수학",grade: "A"}
s.InputSungjuk("과학","c")
s.PrintSungjuk();
}
s를 포인터형으로 받으면 해결됨!!!
*Student로 바꿔주면 됨
package main
import "fmt"
type Student struct {
name string
age int
grade string
class string
}
func (s *Student) PrintSungjuk(){
fmt.Println(s.class,s.grade)
}
func (s *Student) InputSungjuk(class string, grade string){
s.class = class
s.grade =grade
}
func main(){
var s Student= Student{name: "t",age:23, class: "수학",grade: "A"}
s.InputSungjuk("과학","c")
s.PrintSungjuk();
}
결과가 과학,c로 잘 나옴
복사될 때 student 메모리의 주소만 복사 되는거
s는 메모리 주소값을 가지고 있는거
s.class 한거는
s 메모리 주소값이 가르키고 있는 값의 class를 변경.
C++에서는
메모리 주소가 가르키는 값의 뭘 변경하고 싶을 때
p->grade = "c" 이런 식으로 씀(-> 포인터 앞에 이 화살표 사용)
값value 형태에만 . 점 찍을 수 있음
(값)s.grade
고랭에서는 화살표랑 점 구분 안해
p.grade = "c" 포인터여도 점
s.grade ="c" 그냥 내부 값이어도 점
structure 만들고 그안에 속성넣고
기능도 만들었을 때
그 기능이 그 값의 내용을 변경한다 할때는
값의 형태가 아니라 포인터의 형태로 받는다는거!
포인터 형태로 호출하면 메모리 주소만 복사 된다
값 형태로 호출하면, 인자를 값 형태로 받으면 전체 값이 다 복사 된다
강의 좋구만~~