前端算法能力提高(树,链表)

二叉树

对于算法题,树的遍历确实是经常考的(这里我们只讲二叉树哈,二叉树就是指除了叶子节点外,其余节点都有两个子节点)。一般就是前序遍历,中序遍历和后序遍历。所谓的前,中,后其实就是指什么时候遍历根节点。

遍历
如图:这就是一个二叉树,什么是前序遍历呢?前序遍历就是先遍历根节点,再遍历左子树,最后遍历右子树。我一般实现二叉树遍历喜欢使用递归。以我们这个图为例,前序:先遍历根节点:A,再遍历左子树:左子树是B所在分支,这时候可以把B当做A,进行递归。结果是:ABDECFG;

递归思路
递归其实就是直接或者间接自己调用自己,有一个出口(要是没有出口会出现死循环)这个出口就是判断他是不是叶子节点,如果是叶子节点意味着他没有左右子树。

代码实现:

  const root = {
            val: "A",
            left: {
                val: "B",
                left: {
                    val: "D"
                },
                right: {
                    val: "E"
                }
            },
            right: {
                val: "C",
                left:{
                    val:"F",
                },
                right: {
                    val: "G"
                }
            }
        };

        function preorder(root){
            if(!root){
                return
            }
            console.log(root.val)
            preorder(root.left)      
            preorder(root.right)
        }
        preorder(root)

同理:
如果是中序的话,那我们就先遍历左子树,再遍历根节点,最后遍历右子树。
代码实现:

  function preorder(root){
            if(!root){
                return
            }
            preorder(root.left)  
            console.log(root.val)    
            preorder(root.right)
        }
        preorder(root)

想必到这:后序遍历大家也知道该怎么做了吧,这里就不赘述了。

链表
说到链表,首先大家得知道链表的结构是什么样的:
链表

大家可以看到一个节点包含数据域和指针域,数据域就是这个节点保存的数据,指针域代表下一个结点(后继结点)的引用。在上篇文章中说数组的时候说过,数组他是顺序存储结构,也就是我们定义了一个大小固定的数组,他是占据一个连续的空间,而链表不同,他不是占据连续的空间,类似这样:

链表
js怎么写一个节点呢?简单

  function Node(val){
            this.val = val
            this.next = null
        }

那怎么实现一个链表呢?首先要知道他们之间的联系是通过指针来实现的。就像上边我画的那个图的红箭头就意味着指针。

 function Node(val){
            this.val = val
            this.next = null
        }
        let a = new Node(1)
        let b = new Node(2)
        let c = new Node(3)
        a.next = b
        b.next = c
        console.log(a)

log:
zhizhen

链表的特点其实就是能够快速的添加删除元素,有很多人问:为什么需求是方便添加删除元素我们需要使用链表这种数据结构而不是数组呢?其实答案之前我已经给出了,数组他是顺序存储,占据的是一块连续的存储空间,而链表占据的不连续的,他是靠指针建立的联系。比如当我们在任意位置增加一个元素,如果是数组的话,这个位置之后的元素是不是得都要往后挪一位,那他的空间复杂度就是O(n),而如果是链表的话,我们只需要将前一个节点的指针指向这个需要添加的元素,把刚添加的这个元素的指针指向前一个元素指针指向的元素即可。

还拿上边那个例子,我们怎么在尾部添加一个元素4呢?

 function Node(val){
            this.val = val
            this.next = null
        }
        let a = new Node(1)
        let b = new Node(2)
        let c = new Node(3)
        let d = new Node(4)
        a.next = b
        b.next = c
        c.next = d
        console.log(a)

log:
weibu
怎么往中间添加呢,比如在1和2之间添加一个5

 function Node(val){
            this.val = val
            this.next = null
        }
        let a = new Node(1)
        let b = new Node(2)
        let c = new Node(3)
        let d = new Node(4)
        let e = new Node(5)
        a.next = b
        b.next = c
        c.next = d
        //1和2之间添加一个元素5
        a.next = e
        e.next = b
        console.log(a)

log
zhongjian
删除3呢:
删除
链表经典例题:翻转链表

 function Node(val){
            this.val = val
            this.next = null
        }
        let a = new Node(1)
        let b = new Node(2)
        let c = new Node(3)
        a.next = b
        b.next = c
        let newVal = null
        function reverse(head){
            while(head){
                //把第二个节点存起来
                let temp = head.next
                //把头结点的next置空
                head.next = newVal
                newVal = head
                head = temp
            }
            return newVal
        }
        const cc = reverse(a)
        console.log(cc)

log:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值