• 数据结构基础==数据结构与算法2


    1、数据处理的基本操作:增、删、查
    其中,增和删又可细分为在数据结构中间的增和删,以及在数据结构最后进行增和删,区别在于原始数据的位置是否发生改变。查找又可分为按照位置条件的查找和按照数值特征的查找。

    2、线性表结构的增删查

    • (1)线性表是 n 个数据的有限序列,最常用的是线性链表,即链表。
    • (2)链表有单向链表、循环链表、双向链表、双向循环链表。
    • (3)链表新增、删除操作都比较容易,可以在 O(1)的时间复杂度内完成。但查找操作需要 O(n)的时间复杂度,不管是按照位置条件还是数值条件的查找。然而,链表的新增、 删除操作通常都伴随着查找操作。
    • (4)当数据的元素个数不确定,且需要经常进行数据的新增和删除时,那么链表会比较合 适。
    • (5)线性表案例:
      • 单向链表的翻转:双指针。
      • ②给定一个奇数个元素的链表,查找出这个链表中间位置的结点的数值:暴力方法、快慢指 针方法。
      • ③判断链表是否有环:快慢指针方法。

    3、栈(先进后出的线性表)如何实现增、删、查?

    • (1)栈是个限制版的线性表,限制的功能是,只允许数据从栈顶进出。不管是顺序栈(依赖数组)还是链式栈(依赖链表),对于数据的新增操作和删除操作的时间复杂度都是 O(1),而对于查找操作则需要 O(n)的时间复杂度。
    • (2)栈具有后进先出的特性,当面对的问题需要高频使用新增、删除操作,且新增和删除 操作的数据执行顺序具备后来居上的相反顺序时,栈就是个不错的选择。例如:浏览器页面的前进和后退、括号匹配等问题。

    4、队列(先进先出的线性表)如何实现增删查?

    • (1)队列也是一种加了限制的线性表,它值允许从队尾插入数据,从队头删除数据,通常 有顺序队列(数组方式)和链式队列(链表方式)。队列通常用 front 指针指向队头, 用 rear 指针指向队尾。
    • (2)顺序队列有普通队列和循环队列,循环队列可以防止出现“假溢出”问题。
    • (3)链式队列的头结点不存放数据,是为了避免当队列为空时 front 和 rear 成为野指针。
    • 4)在时间复杂度上,循环队列和链式队列的新增、删除操作都为 O(1),查找操作为 O(n)。 在空间性能方面,循环队列必须有一个固定的长度,因此存储的元素数量有限制且有时会造成空间浪费,而链式队列则更为灵活一些。
    • (5)约瑟夫环可以用循环队列来解决。

    5.数组:如何实现基于索引的查找?

    • (1)链表、栈、队列都是线性表,而数组可以看成线性表的一种推广,属于另外一种数据 结构。
    • (2)数组增删查操作的特点:
      • ①增加:若插入数据在最后,则时间复杂度为 O(1);若不是, 则时间复杂度为 O(n)。
      • ②删除:对应位置的删除,时间复杂度为 O(n)。
      • ③查找:如果 只根据索引值进行查找,则时间复杂度为 O(1);
      • 若根据数值条件进行查找,则时间复 杂度为 O(n)。 (3)数组需要在定义时
    • (3)数组需要在定义时就确定长度,且在内存中是按顺序存储的;而链表的长度灵活可变, 且在内存中随机存储。
    • (4)数组更适合在数据量确定,且较少需要进行数据的增加、删除操作的场景下使用。同 时也更适合在数据对位置敏感的场景下使用。链表对数据的增加、删除操作的时间复 杂度更低。

    6.字符串匹配

    • (1)字符串是由 n 个字符组成的有序整体,字符串的存储结构与线性表相同,也有顺序存储和链式存储两种。
    • (2)字符串增删查的特点:
      • ①增加:和数组非常相似,正常情况下时间复杂度为 O(n),若在最后插入(也叫连接),则为 O(1)。
      • ②删除:同样是 O(n)和 O(1)。
      • ③查找(字符串匹配),若主串的长度为 n,模式串的长度为 m,则时间复杂度为 O(nm)。
    • (3)案例:字符串翻转,给定一个字符串,逐个翻转字符串中每个单词,例如,输入“the sky is blue”,输出“blue is sky the”。
    #include 
    #include 
    #include 
    
    void str_reverse(char *str,char* rev)
    {
    	int len=strlen(str),i,j,left=0,index;
    	for(i=0;i<=len;i++){
    		if(str[i]==''||str[i]=='\0'){
    			index=len-i;
    			for(j=left;j<i;j++){
    				rev[index]=str[j];
    				index++;//直接越位
    			}
    			if(left==0)
    				rev[index]='\0';
    			else
    				rev[insex]='';
    			left=i+1;//左端设置
    		}
    	}
    }
    void main()
    {
    	char str[]="the sky si blue";
    	char* rev=(char*)malloc(strlen(str)+1);
    	str_reverse(str,rev);
    	printf("The outis:%s\n", rev);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    7.树和二叉树:分支关系与层次结构下,如何有效实现增删查?

    • (1)树是由结点和边组成的,不存在环的一种数据结构。

    • (2)相关概念:根结点、父结点、子结点、兄弟结点、叶子结点、深度、层。

    • (3)二叉树:每个结点最多有两个分支,其中有两个特殊类型:

      • ①满二叉树。
      • ②完全二叉树:除了最后一层外,其他层的结点个数都达到最大,并且最后一层的叶 子结点都靠左排列。
        在这里插入图片描述
    • (4)二叉树有两种存储方法:

      • 链式存储法
      • 顺序存储法(下标为 i 的左子结点为 2i,右子 结点为 2i+1)
        在这里插入图片描述
    • (5)二叉树的基本操作:

      • ①遍历:前序遍历、中序遍历、后序遍历。时间复杂地为 O(n)。
      • ②增加和删除:时间复杂度位 O(1)==类似链表
        在这里插入图片描述
    • (6)二叉查找(搜索)树(BST

      • ①任意一个结点的的左子树的每个结点的值都小于该结点的值,右子树的每个结点的 值都大于该结点的值。对二叉查找树进行中序遍历,即可输出一个从小到大的有序数据队列
      • 二叉查找树的查找操作、插入操作(包含查找位置)的时间复杂度为 O(logn)。
      • ③删除操作比较复杂:
        • a.要删除某个叶子结点,则直接删除,将其父结点指针指向 NULL。
        • b.要删除的结点只有一个子结点,则将其父结点指针指向其子结点的指针。
        • c.要删除的结点有两个子结点,第一种方法是找到这个结点的左子树中的最大结点来替换该结点;第二种方法是找到这个结点的右子树中的最小 结点来替换该结点。
    • (7)Trie 树/字典树:根结点不包含字符、其他结点都只包含一个字符;从根结点到某一叶子结点,路径上经过的字符连接起来,即为集合中的某个字符串。

    8.哈希表:高效率查找的利器

    • (1)哈希表也叫散列表,是一种特殊的数据结构,其核心思想是:如果有一种方法,可以实现”地址” = f(关键字)的映射关系,那么就可以快速完成基于数据的数值查找了。但 哈希表不可避免地会产生哈希冲突,即不同的关键字得到相同的地址。
    • (2)常用的设计哈希函数的方法:
      • ①直接定制法:哈希函数为关键字到地址的线性函数,如 H(key) = a * key + b。
      • ②数字分析法:假设关键字集合中的每个关键字 key 都是由 s 位数字组成的,从中提 取分布均匀的若干为组成哈希地址。
      • ③平方取中法:如果关键字的每一位都有重复的数字出现,并且频率很高,就可以先求关键字的平方值,扩大差异,然后取中间几位作为存储地址。
      • ④折叠法:如果关键字的位数很多,可以将关键字分割为几个等长的部分,取它们的 叠加和的值(舍去进位)作为哈希地址。
      • ⑤除留余数法:预先设置一个数 p,然后对关键字进行取余运算,即地址 为 key mod p。
    • (3)常用解决哈希冲突的方法:
      • 开放定址法:当一个关键字和另一个关键字产生冲突时,使用某种探测技术在哈希表中形成一个探测序列,然后沿着这个探测序列一次查找下去,当碰到空的单元时则插入其中。常用的探测方法是线性探测法
      • ②链地址法:将哈希地址相同的记录存储在一张线性链表中。(拉链法
    • (4)哈希表可以提供非常快速的插入、删除、查找,无论多少数据,插入和删除只需要接 近常量的时间,查找的速度比树还快。但哈希表中的数据没有顺序的概念,同时 key 是不允许重复的。
    • (5)在很多高级语言中,哈希函数、哈希冲突都已完成了黑盒化处理,是不需要开发者自 己设计的。
  • 相关阅读:
    ros使用catkin_make编译报错Could NOT find PY_em (missing: PY_EM)
    燕之屋通过港交所聆讯:苦战IPO十余年,黄健等人提前精准套现
    创建环境时提示:ERROR conda.core.link:_execute(502)
    建模杂谈系列171 APIFunc继续实践-数据处理体系2
    C++笔记 04
    x86-Hardware-Compatibility-Assessment-and-Porting-Guide
    虚拟人能否代替直播带货?
    docker容器启动成功外部访问不到
    跨境电商如何防关联?3分钟教会你
    SpringMVC执行流程
  • 原文地址:https://blog.csdn.net/weixin_47397155/article/details/126233587