zoukankan      html  css  js  c++  java
  • 数组与链表算法

    数组

    静态数组扩容

    //定义一个结构体模拟数组
    type Array struct {
    	data []interface{} //存放数据
    	size int //已使用的容量
    }
    
    func NewArray(capacity int) *Array{
    	arr := &Array{}
    	arr.data = make([]interface{},capacity)
    	arr.size = 0
    	return arr
    }
    
    //扩容:申请一个新空间,把遍历旧空间,把数据搬运过去
    func (this *Array)resize(newCapacity int){
    	newArr := make([]interface{},newCapacity)
    	for i:=0; i<this.size; i++ {
    		newArr[i] = this.data[i]
    	}
    	this.data = newArr
    }
    //增加一个新元素
    func (this *Array)add(index int,element interface{}){
    	if index < 0 || index > this.size {
    		panic("error index")
    	}
    	//已用空间==容量 触发扩容
    	if len(this.data) == this.size {
    		this.resize(this.size*2)
    	}
    	//把index后的数据全部都后移一个位置
    	for i:=this.size-1; i>=index; i-- {
    		this.data[i+1] = this.data[i]
    	}
    	this.data[index] = element
    	this.size++
    }
    
    

    链表

    type Node struct {
    	data interface{}
    	next *Node
    }
    
    type List struct {
    	head *Node
    }
    
    func NewNode(data interface{})*Node{
    	return &Node{
    		data:data,
    		next:nil,
    	}
    }
    /**
    在指定节点后插入一个数据(要判断传入的节点是否为空)
     */
    func (this *List)InsertAfer(node *Node,newValue interface{}) bool{
    	if node == nil{
    		return false
    	}
    	newNode := NewNode(newValue)
    	newNode.next = node.next
    	node.next = newNode
    	return true
    }
    
    /**
    插入一个节点(主要需要区分插入的是不是第一个节点)
     */
    func (this *List)Insert(newValue interface{}) bool{
    	newNode := NewNode(newValue)
    	if this.head == nil{
    		this.head = newNode
    	}else{
    		//循环找最后一个节点
    		p := this.head
    		for p.next != nil{
    			p = p.next
    		}
    		//节点的指针变换(关键要防止丢指针)
    		newNode.next = p.next
    		p.next = newNode
    	}
    	return true
    }
    
    /*
    删除一个节点
    */
    
    func (this *List)DeleteNode(node *Node) bool{
    	//链表为空或者传入的节点为空,返回false
    	if this.head == nil || node == nil {
    		return false
    	}
    	//特殊处理第一个节点
    	if this.head == node {
    		this.head = this.head.next
    		return true
    	}
    	//以第二个节点为当前节点
    	prev := this.head
    	cur := prev.next
    	//下一个节点非空 继续往下找
    	//如果当前节点已经是目标节点才停止
    	for cur.next != nil && node != cur {
    		prev = cur
    		cur = cur.next
    	}
    	prev.next = cur.next
    	return true
    }
    
    
    /**
    循环链表(关键是怎么判断到最后一个元素)
    */
    type LoopList struct {
    	head *Node
    }
    
    func (this *LoopList) add(value interface{}){
    	newNode := NewNode(value)
           //特殊处理头节点
    	if this.head == nil{
    		this.head = newNode
    		newNode.next = this.head
    	}else{
    		p := this.head
                    //下一个元素是头元素,则该元素是就是要找的尾元素,结束循环
    		for p.next != this.head {
    			p = p.next
    		}
    		newNode.next = p.next
    		p.next = newNode
    	}
    }
    */
    
    /**
    链表反转
    前驱指针和后驱指针构成,每次循环把后驱指针指向到前驱指针
    */
    func reverseList(head *ListNode) *ListNode {
       //前驱指针默认为空
       var pre *ListNode = nil
       //把头指针作为当前指针,只要当前指针不为空,表示有数据
       var cur = head
       for cur != nil {
           //临时保存后驱指针
           tmp := cur.Next
           //后驱指针指向 前一个数据
           cur.Next = pre
           //更新数据,下一个数据的cur就是当前的pre
           pre = cur
           cur = tmp
       }
       //最后一个cur是赋值给了pre,如果返回cur,指针是空的
        return pre
    }
    
    /**
     * Definition for singly-linked list.
     * type ListNode struct {
     *     Val int
     *     Next *ListNode
     * }
     */
    
     /**
    两个有序链表合并成一个
     解题思路:
     1.用哨兵简化插入
     2.两个节点比较,把哨兵指向到数字小的节点,然后节点往后走一步,再重复比较。
     3.每次比较后哨兵都要往后走一步,指向到正确的位置
     4.走到最后哨兵是停留在最后一个位置,所以需要一开始就保存好哨兵的头
     */
    func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
        //哨兵节点,不存数据,为了插入的时候更方便
        preHead := &ListNode{}
        //把头节点暂存
        result := preHead
        //判断哪个节点的数据小,就把哨兵指向该节点,同时该节点偏移到下一个
        for l1 != nil && l2 != nil {
            if l1.Val < l2.Val{
                preHead.Next = l1
                l1 = l1.Next
            }else{
                preHead.Next = l2
                l2 = l2.Next
            }
            //哨兵节点偏移到下一个
            preHead = preHead.Next
        }
        //l1 或者 l2 有剩余数据,直接用哨兵指向他就可以了
        if l1 != nil {
            preHead.Next = l1
        }
        if l2 != nil{
            preHead.Next = l2
        }
        //哨兵的后一个节点
        return result.Next
    }
    
    
    /**
     * 需要考虑奇偶数的情况,奇数fast.Next生效,偶数fast生效
     * 快指针可以前进的条件是:当前快指针和当前快指针的下一个结点都非空。
    */
    func middleNode(head *ListNode) *ListNode {
       slow := head
       fast := head
    
       //奇数: 1 
       //第一轮: fast.Next != nil 生效,循环结束
       //偶数: 1 -> 2
       //第一轮:slow == 2 ,fast != nil 生效,循环结束 
       for fast != nil && fast.Next != nil {
           slow = slow.Next
           fast = fast.Next.Next
       }
       return slow
    }
    
  • 相关阅读:
    Linux_KVM虚拟机
    Linux_KVM虚拟机
    Python_编程特色
    Python_编程特色
    Linux_进程管理&计划任务
    Linux_进程管理&计划任务
    Linux_系统破坏性修复实验
    Linux_系统破坏性修复实验
    Linux_Shell基础
    Confluence 6 的高级 Crowd 设置
  • 原文地址:https://www.cnblogs.com/jaychan/p/13034437.html
Copyright © 2011-2022 走看看