Go语言-实现单链表反转算法
头插法与尾插法
头插法
概念
通过控制插入的位置,每次让新插入的结点放在头结点的后继当中,而新加入的结点还需要连接上原来头结点的原本的后继
特点
插入的顺序与最后链表形成的顺序相反(这样就可以实现自我的反转)
核心过程
p = L->next; //保存原链表的后继 L->next = NULl; //将原链表的后继置为空 //当p非空时,使用q作为插入的结点 q = p; p = p->next; //p指针后移,用以实现后面的循环,不至于断链 q->next = L->next; //这两句实现q结点的插入 L->next = q;
Go语言实现
func Reverse(node *LNode) { p := node.Next //保存原链表的后继 node.Next = nil //将原链表的后继置为空 for p != nil { //循环进行头插法的过程 q := p p = p.Next //指向后面的位置,用作下一轮使用 //下面两句是用来实现头插法的 q.Next = node.Next node.Next = q } }
注意:上述方法是带头指针的头插法的实现,如果是带头节点的头插法需要做一定的修改
如果是带头节点的,则说明node指向的就是第一个节点,如果不做修改则:1 2 3 4 5 -> 1 5 4 3 2 可以看到头节点上的值是没有做逆序的,方法是,可以定义一个新的节点,其next指向题目所给的node
func Reverse(node *LNode)*LNode{ newNode := &LNode{ 0,node} p := head newNode.next = nil for p!=nil{ q:=p p = p.next q.next = newNode.next newNode.next = q } return newNode.next }
【注】C++实现带头节点的单链表反转
LNode* newhead; LNode* next; while(head!=nil){ next = head.next; head.next = newhead; newhead = head; head = next; } return newhead;
返回值为newNode.next
尾插法(补充)
概念
将新加入的结点放在链表最后,并不断更新最后的指针,使其始终可以指向最后结点,以保证后面新结点的插入
特点
插入的顺序与最后形成链表的顺序一致
核心过程
//s作为要插入的节点,r指向最后结点 r->next = s r = s
Go语言实现单链表反转的源码
package main import ( "fmt" . "github.com/isdamir/gotype" ) //思路:可以利用头插法的特点:插入顺序与最后形成的链表顺序相反 /* 将链表中的每个位置的数据取取出来,新建一个表头 使用头插法进行插入 这样只需遍历一次原列表O(n),并且空间复杂度仅为O(1) */ func Reverse(node *LNode) { p := node.Next //保存原链表的后继 node.Next = nil //将原链表的后继置为空 for p != nil { //循环进行头插法的过程 q := p p = p.Next //指向后面的位置,用作下一轮使用 //下面两句是用来实现头插法的 q.Next = node.Next node.Next = q } } func main() { head := &LNode{ } fmt.Println("逆序") CreateNode(head, 8) PrintNode("逆序前:", head) Reverse(head) PrintNode("逆序后:", head) }