Skip to content
标签
数据结构
字数
2910 字
阅读时间
12 分钟

一、概述

数据结构就是把数据元素按照一定的关系组织起来的集合,用来组织和存储数据。

可以把数据结构分为逻辑结构和物理结构两大类。

  • 逻辑结构分类:

    a.集合结构:集合结构中数据元素除了属于同一个集合外,他们之间没有任何其他的关系。

    b.线性结构:线性结构中的数据元素之间存在一对一的关系

    c.树形结构:树形结构中的数据元素之间存在一对多的层次关系

    d.图形结构:图形结构的数据元素是多对多的关系

  • 物理结构分类

    逻辑结构在计算机中真正的表示方式(又称为映像)称为物理结构,也可以叫做存储结构。常见的物理结构有顺序存储结构、链式存储结构

    顺序存储结构:把数据元素放到地址连续的存储单元里面,其数据间的逻辑关系和物理关系是一致的 ,比如我们常用的数组就是顺序存储结构

    链式存储结构:是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的也可以是不连续的。此时,数据元素之间并不能反映元素间的逻辑关系,因此在链式存储结构中引进了一个指针存放数据元素的地址,这样通过地址就可以找到相关联数据元素的位置

算法

算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。研究算法的最终目的就是如何花更少的时间,如何占用更少的内存去完成相同的需求

算法时间复杂度

执行次数=执行时间

用大写O()来体现算法时间复杂度的记法,我们称之为大O记法。

1.用常数1取代运行时间中的所有加法常数;

2.在修改后的运行次数中,只保留高阶项;

3.如果最高阶项存在,且常数因子不为1,则去除与这个项相乘的常数;

描述增长的数量级说明举例
常数级别1普通语句将两个数字相加
对数级别logN二分策略二分查找
线性级别N循环找出最大元素
线性对数级别NlogN分治思想归并排序
平方级别N^2双层循环检查所有元素
立方级别N^3三层循环检查所有三元组
指数级别2^N穷举查找检查所有子集

他们的复杂程度从低到高依次为:

O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)

空间复杂度

标识对内存的占用 分析同时间复杂度。

二叉树

树的定义及特点

树的定义

​ 树是由n(n>=1)个有限节点组成的一个具有层次关系的集合。

树的特点:

  1. 每个节点有零个或多个子节点;

  2. 没有父节点的节点称为根节点;

  3. 每一个非根节点有且只有一个父节点;

  4. 除了根节点外,每个子节点可以分为多个不相交的子树。

二叉树概念及特点:

二叉树是一种特殊的树,在树的基础上添加约束条件:每个节点下最多只有两棵子树。它具有特点:

  1. 每个节点最多有两颗子树。

  2. 左子树和右子树是有顺序的,次序不能颠倒。

  3. 即使某节点只有一个子树,也要区分左右子树。

二叉树实现

一个二叉树节点有三个部分,一个是指向左子树的部分,一个是指向右子树的部分,另外一个是数据部分。可以把这个节点抽象成一个节点对象,节点对象有两个节点对象属性和一个数据属性。

一个二叉树有且只有一个根节点,其余的都是根节点的直接或间接子节点。所以可以把二叉树抽象成一个对象,该对象有一个节点类型的数据,用来保存根节点。

以java实体类为例

java
/**
 * 节点类
 * @author pkxing
 *
 */
public class Node {
	// 节点内容
	int  value;
	// 左节点
    Node leftChild;  
    // 右节点
    Node rightChild;  
    
    public Node(int value) {  
        this.value = value;  
    }  
    @Override  
    public String toString() {  
        return String.valueOf(value);  
    }    
}
java
/**
 * 二叉树类
 * @author pkxing
 *
 */
public class BinaryTree {
	// 根节点
	private Node root = null;
	// 构造方法
	// 有参数
	public BinaryTree(int value) {  
        root = new Node(value);  
        root.leftChild  = null;  
        root.rightChild = null;  
    }  
	// 无参数
	public BinaryTree(){}
}

二叉树操作

二叉排序树的本质就是一颗二叉树,它具有如下特点:

所有左节点的元素值小于其父节点的元素值.

所有右节点的元素值大于其父节点的元素值.

添加节点

java
	// 二叉树类中方法。
	/**
	* 插入节点
	* @param value  节点的值
	* @return 插入成功返回true,否则返回false
	*/
	public boolean add(int value) {
		// 定义变量用来标识是否插入成功,默认值表示插入成功
		boolean success = true;
		// 根据内容创建节点对象
		Node node = new Node(value);
		// 判断根节点是否为null,如果为null,则将node对象作为根节点对象
		if (root == null) { // 没有根节点
			// 将node对象作为根节点对象
			root = node;
			// 设置左右节点为null
			root.leftChild = null;
			root.rightChild = null;
		} else { // 有根据节点
			// 定义变量记录当前遍历的节点对象:默认从根节点对象开始遍历
			Node current = root;
			// 遍历树上的所有节点对象
			while (true) {
				if (value < current.value) {
					// 来到这里说明node对象应该添加到current节点对象的左边
					if (current.leftChild == null) {
						current.leftChild = node;
						break;
					}
					// 获得current节点的左子节点对象,并赋值给current变量
					current = current.leftChild;
				} else if (value > current.value) {
					// 来到这里说明node对象应该添加到current节点对象的右边
					if (current.rightChild == null) {
						current.rightChild = node;
						break;
					}
					// 获得current节点的右子节点对象,并赋值给current变量
					current = current.rightChild;
				} else { // value值已经存在了,则直接返回false
					success = false;
					break;
				}

		}
		// 插入成功
		return success;
}

查询节点

先查找其根节点,如果根节点的元素值和要查找的元素值相等,则返回该根节点对象。否则,比较根节点的元素和要查找的元素,

​ 如果元素值大于根节点元素值,则查询其右子树。

​ 如果元素值小于根节点元素值,则查询其左子树。

java
	// 二叉树类中添加方法
	/**
	* 根据节点内容查找节点对象
	* @param value 内容
	* @return 查找到的节点对象,如果没有则返回null
	*/
	public Node get(int value) {  
		// 定义变量记录当前遍历的节点对象,默认从根节点开始遍历
	    Node current = root;  
	    while (true) {  
	    	// 判断value和current节点对象的value是否相同
	        if (value == current.value) {  
	        	// 来到这里则说明current节点对象就是要查找的对象,直接返回即可
	            return current;  
	        } else if (value < current.value) {  
	        	// 来到这里说明要查找的节点对象是在current节点的左子树上
	            current = current.leftChild;  
	        } else if (value > current.value) {  
	        	// 来到这里说明要查找的节点对象是在current节点的右子树上
	            current = current.rightChild;  
	        } 
	        // 如果current节点对象为null,则说明没有找到对应的节点对象
	        if (current == null) {  
	            return null;  
	        }  
	    }  
	}

遍历

遍历流程:先遍历左子树,再访问根节点,最后遍历右子树

java
	// 二叉树类中添加方法
	/**
	* 先遍历左子树,再访问根节点,最后遍历右子树;

	* @param node
	*/
	public void inOrder(Node node) { 
		if (node != null) {
			inOrder(node.getLeftChild());
			System.out.println(node);
			inOrder(node.getRightChild());
		}
	}

	/**
	 * 将指定节点下的所有子节点的内容按顺序输出
	 * @param node
	 */
	public void order2(Node node,List<Integer> list){
		if(node == null) return;
		// 先遍历node的左节点
		order2(node.getLeftChild(),list);
		// 将节点内容添加集合中
		list.add(node.getValue());
		// 遍历node的右节点
		order2(node.getRightChild(),list);
	}
	
	@Override
	public String toString() {
		// 创建集合对象
		List<Integer> list = new ArrayList<>();
		order2(root,list);
		return list.toString();
	}

平衡二叉树

为了避免出现"瘸子"的现象,减少树的高度,提高我们的搜素效率,又存在一种树的结构:"平衡二叉树"

​ 它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

平衡二叉树的旋转

  • 概念:

​ 在构建一棵平衡二叉树的过程中,当有新的结点要插入时,检查是否因插入后而破坏了树的平衡,如果是,则需要做旋转去改变树的结构。

  • 两种旋转方式:

    • 左旋:

      左旋就是将结点的右支往左拉,右子结点变成父结点,并把晋升之后多余的左子结点出让给降级结点的 右子结点;

    • 右旋:

      将结点的左支往右拉,左子结点变成了父结点,并把晋升之后多余的右子结点出让给降级结点的左子结 点

  • 四种失衡情况:

    • 左左情况,需要以10为基准结点进行右旋

    • 左右情况,先以7为基准结点进行左旋,再以11为基准结点进行右旋

    • 右左情况,先以15为基准结点进行右旋,再以11为基准结点进行左旋

    • 右右情况,以11未基准结点进行左旋

红黑树

  • 概述:

    红黑树是一种自平衡的二叉查找树。

    红黑树的每一个结点上都有存储位表示结点的颜色,可以是红或者黑。

    红黑树不是高度平衡的,它的平衡是通过"红黑树的特性"进行实现的。

  • 红黑树的特性:

    1. 每一个结点或是红色的,或者是黑色的;
    2. 根结点必须是黑色;
    3. 每个叶结点是黑色的(叶结点是Nil)
    4. 如果某一个结点是红色,那么它的子结点必须是黑色(不能出现两个红色结点相连的情况)
    5. 对每一个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点;
  • 图: