链与二叉树

1.链

1.1 什么是链表?

链表 [Linked List]:链表是由一组不必相连(不必相连:可以连续也可以不连续)的内 存结构(节点),按特定的顺序链接在一起的抽象数据类型。

补充: 抽象数据类型(Abstract Data Type [ADT]):表示数学中抽象出来的一些操作的集合。 内存结构:内存中的结构,如:struct、特殊内存块...等等之类;

//链表节点
class Node{
    Object date;
    Node next;
}

数组和链表的区别和优缺点:

数组是一种连续存储线性结构,元素类型相同,大小相等

数组的优点: 存取速度快

数组的缺点: 事先必须知道数组的长度 插入删除元素很慢 空间通常是有限制的 需要大块连续的内存块 插入删除元素的效率很低

链表是离散存储线性结构 n 个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一 个后续节点,首节点没有前驱节点,尾节点没有后续节点。

链表优点: 空间没有限制 插入删除元素很快

链表缺点: 存取速度很慢

1.2 链表共分几类?

链表常用的有 3 类: 单链表、双向链表、循环链表。

 

链表的核心操作集有 3 种:插入、删除、查找(遍历)

单链表 [Linked List]:

由各个内存结构通过一个 Next 指针链接在一起组成,每一个内 存结构都存在后继内存结构(链尾除外),内存结构由数据域和 Next 指针域组成。

 

解析:

Data 数据 + Next 指针,组成一个单链表的内存结构 ; 第一个内存结构称为 链头,最后一个内存结构称为 链尾; 链尾的 Next 指针设置为 NULL [指向空]; 单链表的遍历方向单一(只能从链头一直遍历到链尾) 单链表操作集:

 

双向链表 [Double Linked List]:

由各个内存结构通过指针 Next 和指针 Prev 链接在一 起组成,每一个内存结构都存在前驱内存结构和后继内存结构(链头没有前驱,链尾没有后 继),内存结构由数据域、Prev 指针域和 Next 指针域组成。

双向链表实现图示:

 

解析:

  • Data 数据 + Next 指针 + Prev 指针,组成一个双向链表的内存结构;

  • 第一个内存结构称为 链头,最后一个内存结构称为 链尾;

  • 链头的 Prev 指针设置为 NULL, 链尾的 Next 指针设置为 NULL;

  • Prev 指向的内存结构称为 前驱, Next 指向的内存结构称为 后继;

  • 双向链表的遍历是双向的,即如果把从链头的 Next 一直到链尾的[NULL] 遍历方向定 义为正向,那么从链尾的 Prev 一直到链头 [NULL ]遍历方向就是反向;

双向链表操作集:

 

循环链表

单向循环链表 [Circular Linked List] : 由各个内存结构通过一个指针 Next 链接在一起 组成,每一个内存结构都存在后继内存结构,内存结构由数据域和 Next 指针域组成。

双向循环链表 [Double Circular Linked List] : 由各个内存结构通过指针 Next 和指针 Prev 链接在一起组成,每一个内存结构都存在前驱内存结构和后继内存结构,内存结构由 数据域、Prev 指针域和 Next 指针域组成。

循环链表的单向与双向实现图示:

解析:

  • 循环链表分为单向、双向两种;

  • 单向的实现就是在单链表的基础上,把链尾的 Next 指针直接指向链头,形成一个闭环;

  • 双向的实现就是在双向链表的基础上,把链尾的 Next 指针指向链头,再把链头的 Prev 指针指向链尾,形成一个闭环;

  • 循环链表没有链头和链尾的说法,因为是闭环的,所以每一个内存结构都可以充当链头 和链尾;

循环链表操作集

 

2.二叉树

2.1 什么是二叉树

二叉树是树的一种,每个节点最多可具有两个子树,即结点的度最大为 2(结点度:结点拥 有的子树数)。

 

二叉树就是每个节点不能多于有两个儿子,上面的图就是一颗二叉树,而且还是一种特殊的二叉树:

2.2 二叉查找树(binary search tree)。

定义:当前根节点的左边全部比根节点小,当前根节点的右边全部比根节点大。 

一棵树至少会有一个节点(根节点)

树由节点组成,每个节点的数据结构是这样的

  因此,我们定义树的时候往往是**->定义节点->节点连接起来就成了树**,而节点的定义就是:一个数据、两个指针(如果有节点就指向节点、没有节点就指向 null)

 

2.3 二叉树的一些性质

  • 1.二叉树第 i 层上的结点数目最多为 2^(i-1) (i≥1)
  • 2.深度为 h 的二叉树至多有 2^h-1 个结点(h≥1)
  • 3.包含 n 个结点的二叉树的高度至少为 log2 (n+1)
  • 4.在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1

2.4二叉树的遍历方式

二叉树的遍历方式,一般分为先序遍历,中序遍历,后序遍历。

先序遍历 o   先访问根节点,然后访问左节点,最后访问右节点(根->左->右) •  

中序遍历 o   先访问左节点,然后访问根节点,最后访问右节点(左->根->右) •    

后序遍历 o   先访问左节点,然后访问右节点,最后访问根节点(左->右->根)

先序遍历(根-左-右):1-2-4-8-9-5-10-3-6-7

中序遍历:(左-根-右):8-4-9-2-10-5-1-6-3-7

后序遍历(左-右-根):8-9-4-10-5-2-6-7-3-1

一、前序遍历

  访问顺序:先根节点,再左子树,最后右子树;上图的访问结果为:GDAFEMHZ。

  1)递归实现

public void preOrderTraverse1(TreeNode root) {
        if (root != null) {
            System.out.print(root.var + "->");
            preOrderTraverse1(root.left);
            preOrderTraverse1(root.right);
        }
    }

2)非递归实现

public void preOrderTraverse2(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.empty()) {
            if (node != null) {
                System.out.print(node.var+ "->");
                stack.push(node);
                node = node.left;
            } else {
                TreeNode tem = stack.pop();
                node = tem.right;
            }
        }
    }

二、中序遍历

  访问顺序:先左子树,再根节点,最后右子树;上图的访问结果为:ADEFGHMZ。

  1)递归实现

public void inOrderTraverse(TreeNode root) {
        if (root != null) {
            inOrderTraverse(root.left);
            System.out.print(root.val + "->");
            inOrderTraverse(root.right);
        }
    }

2)非递归实现

public void inOrderTraverse(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.left;
            } else {
                TreeNode tem = stack.pop();
                System.out.print(tem.val + "->");
                node = tem.right;
            }
        }
    }

三、后序遍历

  访问顺序:先左子树,再右子树,最后根节点,上图的访问结果为:AEFDHZMG。

  1)递归实现

public void postOrderTraverse(TreeNode root) {
        if (root != null) {
            postOrderTraverse(root.left);
            postOrderTraverse(root.right);
            System.out.print(root.val + "->");
        }
    }

2)非递归实现

public void postOrderTraverse(TreeNode root) {
        TreeNode cur, pre = null;

        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);

        while (!stack.empty()) {
            cur = stack.peek();
            if ((cur.left == null && cur.right == null) || (pre != null && (pre == cur.left || pre == cur.right))) {
                System.out.print(cur.val + "->");
                stack.pop();
                pre = cur;
            } else {
                if (cur.right != null)
                    stack.push(cur.right);
                if (cur.left != null)
                    stack.push(cur.left);
            }
        }
    }

四、层次遍历

  访问结果:GDMAFHZE。

public void levelOrderTraverse(TreeNode root) {
        if (root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);

        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            System.out.print(node.val + "->");

            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
    }

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值