728x90
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)
// }
728x90
728x90

https://youtu.be/r1_G9ayX980

d

동적배열 종류

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)


}

 

 

 

728x90
728x90
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 만들고 그안에 속성넣고

기능도 만들었을 때

 

그 기능이 그 값의 내용을 변경한다 할때는

값의 형태가 아니라 포인터의 형태로 받는다는거!

 

 

 

포인터 형태로 호출하면 메모리 주소만 복사 된다

값 형태로 호출하면, 인자를 값 형태로 받으면 전체 값이 다 복사 된다

 

 

 

 

 

강의 좋구만~~

 

https://youtu.be/nBAKHq12kew

 

728x90

+ Recent posts