从头部(尾部)开始某个位置前插入新节点
三种情况进行插入新节点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLBQrF4k-1684332357909)(C:\Users\27198\AppData\Roaming\Typora\typora-user-images\image-20230513151555431.png)]
// AddNodeFromHead 就是从头开始进行添加节点到N+1个元素之前
// N=0表示添加到第一个元素之前,表示新节点成为新的头部,
// N=1表示添加到第二个元素之前,以此类推
func (list *DoubleList) AddNodeFromHead(n int, v string) {
list.lock.Lock()
defer list.lock.Unlock()
//首先进行相关判断,如果索引长度超过列表长度,一定找不到,直接panic
if n != 0 && n >= list.len {
panic("index out!!!")
}
//首先找到头节点
node := list.head
//然后依次往后进行遍历操作
for i := 0; i < n; i++ {
node = node.next
}
//创建新节点
newNode := new(ListNode)
newNode.value = v
//然后进行节点插入操作
//如果定位到的节点为空,表示列表为空,将新节点设置为新头部和新尾部
//1.相当于情况1,第一种情况,判断定位到的节点 node 是否为空,如果为空,表明列表没有元素,将新节点设置为新头部和新尾部即可:
if node.IsNil() {
list.head = newNode
list.tail = newNode
} else {
//定位到了节点,它的前驱就是头部的前驱
pre := node.pre
//2.如果定位到的节点前驱为nil,那么定位到的节点就是链表头部,需要换头部
if pre.IsNil() {
//将新节点连接在老头部之前
newNode.next = node
node.pre = newNode
//新节点成为头部
list.head = newNode
} else {
//第三种情况,
//如果定位到的节点的前驱节点不为空,表明定位到的节点 node 不是头部节点,那么我们只需将新节点链接到节点 node 之前即可:
pre.next = newNode
newNode.next = pre
//定位到的节点的后驱节点 node.next现在链接到新节点上
node.next.pre = newNode
newNode.next = node.next
}
}
list.len = list.len + 1
}
// AddNodeFromTail 从尾部开始,添加节点到N+1个元素之后,N=0表示添加到第一个元素之后,表示新节点成为新的尾部,N=1,表示添加第二个元素之后,以此类推
func (list *DoubleList) AddNodeFromTail(n int, v string) {
//加入并发锁
list.lock.Lock()
list.lock.Unlock()
//先进行对应的判断,如果长度超过或等于列表超度,一定就找不到
if n != 0 && n >= list.len {
panic("index out")
}
//先找出尾部
node := list.tail
for i := 0; i < n; i++ {
node = node.pre
}
//创建新节点的相关信息
newNode := new(ListNode)
newNode.value = v
//如果定位到的节点为空,表示列表为空,将新节点设置为新头部和新尾部
if node.IsNil() {
list.head = newNode
list.tail = newNode
} else {
next := node.next
//如果定位到的节点后驱为nil,那么定位到的节点为链表尾部,就需要更换尾部
if next.IsNil() {
node.next = newNode
newNode.pre = node
list.tail = newNode
} else {
//将新节点插入到定位到的节点之后
//新节点链接到定位到的节点之后
newNode.pre = newNode
node.next = newNode
//定位到的节点的后驱节点连接到新节点之后
newNode.next = next
next.pre = newNode
}
}
list.len = list.len + 1
}