初识数据结构(狗都不学)

时间复杂度

介绍

时间复杂度由多项式T(n)中最高阶的项决定

在这里插入图片描述

常见类型

由低到高:
在这里插入图片描述

最差、最佳时间复杂度

在实际应用中很少使用“最佳时间复杂度”,因为往往只有很小高概率才能达到,会带来一定的误导性。反之,“最差时间复杂度”最为实用,因为它给出了一个“效率安全值”,让我们可以放心地使用算法。

空间复杂度

简介

内存空间:

  • 输入空间:存储算法的输入数据。
  • 暂存空间:存储算法运行中的变量、对象、函数上下文等数据。
    • 暂存数据:保存算法运行中的各种常量、变量、对象等。
    • 栈帧空间:保存调用函数的上下文数据;系统每次调用函数都会在栈的顶部创建一个栈帧,函数返回时,栈帧空间会被释放。
    • 指令空间:保存编译后的程序指令,实际统计中一般忽略不计。
  • 输出空间:存储算法的输出数据。

通常,空间复杂度统计范围是 暂存空间 + 输出空间

常见类型

甜点1

尾递归

介绍

函数在尾位置调用自身,或一个尾调用本身的其他函数等,称为尾递归。

特征

  • 在尾部调用的是函数自身;
  • 可通过优化,使得计算仅占用常量栈空间。

数据结构

介绍

  • 计算机中组织与存储数据的方式。
  • 基本数据结构提供了数据的==“内容类型”,数据结构提供数据的“组织方式”==。

分类

  • 逻辑结构

    • 线性:数组、链表、栈、队列、哈希表等。

    • 非线性:树、图、堆、哈希表。在这里插入图片描述

  • 物理结构

    反应了数据在计算机内存中的存储方式。

拓展

  • 所有数据结构都是基于数组、或链表、或两者组合实现的。
    • 基于数组(静态数据结构):栈、队列、哈希表、树、堆、矩阵、张量等
    • 基于链表(动态数据结构):栈、队列、哈希表、树、堆、图等

数组

介绍

  • 将相同类型元素存储在连续内存空间的数据结构。
  • 将元素在数组中的位置称为元素的索引 Index

特点

优点

  • 访问高效。
    在这里插入图片描述

  • 为什么索引从0开始

    • 根据地址计算公式,索引本质上表示的是内存地址偏移量,首个元素的地址偏移量是0,所以索引是0很自然。

缺点

长度不可变。

操作

扩展数组

int[] extend(int[] nums, int enlarge) (
    // 初始化一个扩展长度后的数组
    int[] res = new int[nums.length + enlarge];
    // 将原数组中的所有元素复制到新数组
    for (int i = @; i < nums.length; i++){
        res[i] = nums[i];
    }
    // 返回扩展后的新数组
    return res;
}

插入元素

void insert(int[] nums, int num, int index) (
    // 把索引 index 以及之后的所有元向后移动一位
    for (int i = nums.length - 1; i > index; i--) {
        nums[i] = nums[i - 1];
    }
	// 将 num 赋给 index 处元素
    nums[index] = num;
}

删除元素

void remove(int[] nums, int index) {
    // 把索引 index 之后的所有元素向前移动一位
    for (int i = index; i < nums.length - 1; i++){
 	   nums[i] = nums[i + 1];
    }
} 

遍历

void traverse(int[] nums) {
    int count = 0;
	// 通过索引遍历数组
    for (int i = 0; i < nums.length; i++) {
		count++;
    }
    //直接遍历数组
    for (int num : nums) {
        count++;
    }
}

查找元素

int find(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] == target)
            return i;
    }
return -1;
}

甜点2

  1. 栈内存分配由编译器自动完成,堆内存由程序员在代码中分配。

    1. 栈不灵活,分配的内存大小不可更改;堆相对灵活,可以动态分配内存。
    2. 是一块比较小的内存,易出现内存不足内存很大,但是由于是动态分配,易碎片化,故管理堆内存的难度更大、成本更高。
    3. 访问栈比访问堆更快,因为栈内存较小、对缓存友好,堆帧分散在很大的空间内,会出现更多的缓存未命中。
  2. Java数组内存图在这里插入图片描述

  3. 引用

    • 什么是引用?

      • 引用 = 起个别名;
      • 并不另外开辟内存单元;
      • 占用内存的同一位置。
    • 什么是引用类型?

      • 值类型直接存储其值,而引用类型存储对其值的引用
      • 这个引用指向真事的数组内存,如果数组元素也是引用类型,也就是多维数组

    在这里插入图片描述

链表

介绍

  • 【链表Linked List】是一种线性数据结构,其中每个元素都是单独的对象,各个元素之间通过指针连接
  • 链表的【结点 Node】包含两项数据:
    • 结点【值 Value】
    • 指向下一节点的 【指针 Pointer】,为节点指向【空 null】

特点

优点

插入与删除结点的操作更高效

缺点

链表访问结点效率低

操作

初始化

  1. 初始化各个节点对象

  2. 构建引用指向关系

    // 初始化各个节点
    ListNode ne = new ListNode(1);
    ListNode n1 = new ListNode(3);
    ListNode n2 = new ListNode(2);
    ListNode n3 = new ListNode(5);
    ListNode n4 = new ListNode(4);
    // 构建引用指向
    ne.next = n1;
    n1.next = n2;
    n2.next = n3;
    n3 .next = n4;
    

遍历链表查找

int find(ListNode head, int target) {
    int index = 0;
    while (head != null) {
        if (head.val == target)
            return index;
        head = head.next;
        index++;
    }
	return -1;
}

常见链表类型

  1. 单向链表:即上述介绍的普通链表。
  2. 环形链表
    1. 令单向链表的尾结点指向头结点(即首尾相接),则得到一个环形链表。
    2. 可以将任意节点看作是头节点
  3. 双向链表:同时有指向下一节点和上一结点的指针在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值