数据结构与算法
文章平均质量分 65
主要总结一些常用的数据结构和算法,用C++代码
三公子Tjq
三少爷的剑:剑气纵横三万里,一剑光寒十九洲!
展开
-
设计一个LRU(最近最少使用缓存)结构——C++
本体主要是设计一个LRU结构,LRU主要用在缓存策略上保证最近最少使用的数据页换出,从而提高CPU查找缓存的命中率。题目主要是设计一个结构类型struct Lru{};该类型包含两个成员方法get(int)和set(int,int),且要求这两个方法的时间复杂度为O(1)。查找时间复杂度为O(1)我们一般想到查表,比如std::unordered_map和std::unordered_set,但是题目还要求插入和删除数据也是O(1),这时一般的map和set和vector都不能满足要求,只有链表可以符合要求原创 2022-02-26 20:56:43 · 1162 阅读 · 0 评论 -
查找有序数组(二分法)(时间复杂度O(logn))——C++
查找有序数组指定元素,返回目标元素下标,如果不存在,则插入适当位置使数组仍然保持有序,时间复杂度为O(log(n)),该算法是基本查找算法,可以用二分法。下面是代码实现。class Solution {public: int searchInsert(vector<int>& nums, int target) { int size = nums.size(), left = 0, right = size - 1, mid = 0; while (l原创 2022-01-22 01:00:36 · 1752 阅读 · 0 评论 -
图的并查集QuickFind类总结——C++
图分为无向图、有向图、加权图。其中理解图论中一个重要概念是并查集。并查集有两个重要功能,分别是find查找根节点函数和union连通两个节点。传统的并查集实现算法效率较低,引申出两种优化版的并查集算法,分别是QuickFind类和UnionFind,本文主要介绍QuickFind类的实现。一、类QuickFind介绍1.1 类QuickFind功能和函数类QuickFind主要有两个重要函数,分别是findRoot()和unionNode()。函数findRoot()功能是查找某个节点的根节原创 2022-01-22 00:56:22 · 1122 阅读 · 0 评论 -
二叉树层次遍历(队列法、每层打印)——C++
由上面题目可知,输入是一个一维数组,输出是一个二维数组。其中输入一维数组中存储的是节点元素,输出二维数组是每层节点关键字打印。故知道该题主要考察二叉树基本的层次遍历方法,需要打印出每层节点的关键字。二叉树的层次遍历实现思路是用一个队列记录每层节点,当记录第一层节点时,弹出第一层节点进行访问,访问的同时需要遍历对应节点的左右子节点压栈;当访问完一层节点时,此时改成节点所有左右子节点都已经压栈,由于先前循环弹出了第一层的n个节点,故当前队列只存储下一层所有节点,所以只需要将该队列大小保存,然后该轮循环中弹出这原创 2021-12-08 21:12:47 · 2912 阅读 · 0 评论 -
二叉树后序遍历(递归法和迭代法(非递归法))——C++
一、二叉树后序遍历后序遍历是先遍历左子节点left,在遍历右子节点right,最后遍历父节点parent,即遍历顺序:1.2 迭代法由于后续遍历如果按照正常迭代思路去实现将不好理解和实现,仔细观察下面前序和后续遍历顺序,可以发现一个规律:前序遍历:parent ——> left ——> right前序遍历: left ——> right ——>parent,将后续遍历逆序过来遍历,则:parent ——> right ——>left通过观察1和3可以发现,两者都是先遍历父节点,再遍历左原创 2021-12-04 22:50:25 · 1925 阅读 · 1 评论 -
二叉树中序遍历(递归法和迭代法(非递归法))——C++
1.2迭代法迭代法是采用非递归方法实现二叉树的中序遍历,主要利用数据结构std::stack来实现,利用栈std::stack的先进后出特性依次压入待访问的节点,然后依次按照中序遍历顺序弹出和访问节点,确保每个节点有且仅有一次访问。具体步骤如下:a1 先将所有父节点和左子节点依次压入栈;这样做的目的是为了先弹出左子节点,再弹出父节点,可以在弹出左子节点的时候进行遍历,同时处理右节点,比如将右节点压入栈,这样就实现了先访问左节点,然后父节点,最后右子节点。a2 然后弹出一个节点,进行遍历;此时弹出a原创 2021-12-04 20:45:55 · 1829 阅读 · 1 评论 -
二叉树前序遍历(递归法和迭代法(即非递归法))——C++
一、前序遍历递归法前序遍历递归法主要是先遍历父节点parent,然后遍历左子节点,最后遍历右子节点,具体可以参考博客:二叉树基本知识点图文介绍(全网最简洁)_净无邪博客-CSDN博客。1.1具体解法如下:递归法的要诀是找到递归退出条件和按条件分步进行递归。具体解法比较简单,直接看代码和解释即可理解。二、前序遍历迭代法迭代法,也成为非递归法解前序遍历时,需要依靠一个栈数据结构依次遍历每一个节点。实现方法为将每个节点压入栈。注意,栈是先进后出结构,所以需要先压入右节点,再压入左节点,弹出的时候才能先原创 2021-12-03 22:31:03 · 4306 阅读 · 0 评论 -
二叉树基本知识点图文介绍(全网最简洁)
一、二叉树相关理论1.1定义二叉树是指树中节点的度不超过二的有序树。一棵空树或者一个节点的树也可以称为二叉树,二叉树其左右子树也各种一棵二叉树。1.2基本分类有满二叉树和完全二叉树之分。1.2.1满二叉树是所有非叶子节点都有且仅存在左右子树的二叉树。图一 满二叉树1.2.2完全二叉树是除最后一层非叶子节点外都有且仅存在左右子树,且最后一层叶子节点从左到右紧密排列,右边连续缺少若干个节点的二叉树图二 完全二叉树1.3性质性质1:二叉树第i层至多有(i>0)个节点原创 2021-12-03 22:03:33 · 2546 阅读 · 0 评论 -
桶排序算法——C++
桶排序算法是“分治法”的典型应用,主要思路是先“分桶”(或建捅)再“合桶”。其中最关键的是“分桶”,这一步最佳的时将整个待排序数组均匀分布在每个“分桶”内,然后再对每个“分桶”内部进行排序,最后将所有排序好的“分桶”依次遍历输出即可。这个思路感觉跟“计数排序算法”和“基数排序算法”十分相识。“计数排序”是通过下标将待排序数映射到“一个桶”内,然后再逐个取出;而“基数排序”是遍历所有“基数”,然后对每个基数进行一轮“计数排序”,最后完成整个数组排序。“桶排序”的“分桶”过程也是需要将待排序元素映射到“桶”原创 2021-12-01 23:58:31 · 1787 阅读 · 0 评论 -
基数排序算法——C++
基数排序的主要思想是选择多位基数依次进行排序,利用每次排序后还是相对有序,也就是稳定排序性质,依次比较完所有基数后,完成整个数组排序。其中,每次比较基数比如对整数进行排序时可以采用计数排序,因为整数位数有限并且每个位上的数值范围是0-9,所以最适合采用优化后计数排序对每个基数进行排序。时间复杂度为O(n + m),空间复杂度为O(n + m),其中n为数组个数,m为数组最大值位数。基数排序跟数组规模有关,假如规模很大的话,不一定比快速排序更优,故需要就具体数据模块进行分析。一、代码实现分原创 2021-11-26 23:53:11 · 2754 阅读 · 3 评论 -
计数排序算法——C++
计数排序是时间复杂度为O(n + m)的算法,空间复杂度为O(n + m);算法思想跟散列表哈希hash有些类似,主要是利用一段有序数组计算对应元素的下表个数,然后依次输出有数组元素进行排列。基本计数排序是不稳定算法,但是优化后计数排序是稳定算法。本文主要讲解基本计数排序和优化后计数排序。使用条件:数组必须是整数或者能全部映射为整数,数组所有元素必须在有限较集中范围;一、具体实现步骤1.计算原始数组的最大值max和最小值min范围,然后创建一个长度为max--min+1的排序数组sortAr原创 2021-11-24 23:48:56 · 3392 阅读 · 4 评论 -
希尔排序算法——C++
希尔排序是第一个在空间复杂度为O(1)条件下,将数组排序的时间复杂度降到O(logn^2)的算法,具有巨大历史意义,为后面的堆排序,快速排序提供了极大的启发和参考。故希尔排序时间复杂度为O(logn^2),空间复杂度为O(1)。希尔排序是对插入排序的一种改进算法,由于插入排序只在数据较少且基本有序时效率才是最佳的,故希尔排序原理将整个数组分为多个分组,然后分别进行排序。分组的其中一个原则是两个分组的元素尽量间隔较远,以消除逆序对,提高排序效率。由上一篇的堆排序可知,排序本质是对逆序对的消除,堆排序就原创 2021-11-18 00:01:58 · 3335 阅读 · 6 评论 -
插入排序算法——C++
插入排序算法主要是将待排序数组依次插入有序数组中,时间复杂度是O(logn^2),空间复杂度为O(1);下面是代码实现步骤:1.先假定数组左边第一个元素是有序的void Sorts::insert(vector<int>& nums){ if (nums.size() <= 1) return; ......}2.依次遍历待排数组的右边第二个元素到最后一个元素void Sorts::insert(vector<int原创 2021-11-13 18:06:26 · 2029 阅读 · 0 评论 -
求数组中的逆序对(时间复杂度为O(nlogn))C++代码实现
求数组中的逆序对,要求时间复杂度为O(nlogn),空间复杂度O(n)题目如下:(注:原题来自力扣的剑指 Offer 51. 数组中的逆序对)在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。示例 1:输入: [7,5,6,4]输出: 5思路分析:1.如果不考虑时间复杂度限制,则可以考虑暴力解法,即用双层循环即可遍历整个数组完成逆序对统计。int reversePairs(vector<int&g原创 2021-11-11 00:17:13 · 1122 阅读 · 0 评论 -
归并排序算法(优化版)——C++
关于归并排序的介绍可以参考这边博客:归并排序算法(经典返回变量版)——C++_净无邪博客-CSDN博客。本文主要是对递归排序进行优化。由于经典版本返回临时变量的归并排序效率比较低,需要多每次创建临时空间进行优化,使用一个固定内存空间,这样可以减少每次创建和销毁内存空间的时间消耗,由于这部分很费时间,所以优化效果是比较明显的。优化版跟基本版的区别主要区别如下:1.归并函数原来是入参两个数组,优化后入参为两个待排序数组合并在一起的起始和截止位置,如下所示:void merge1(vector&原创 2021-11-07 00:36:02 · 1181 阅读 · 0 评论 -
归并排序算法(经典返回临时变量版)——C++
归并排序算法思想主要是将两个有序数组合并成为一个有序数组,其关键点采用“分治思想”,“分”是二分法,将无序数组分割成为一个个有序数组,然后通过“治” 将两个有序数组合并成为一个有序数组。时间时间复杂度为为O(nlogn),空间复杂度是O(n)的常量级临时变量,是稳定排序算法。归并排序主要实现思想:采用“分治思想”,先“分”将整个无序数组先左边递归,再右边递归,类似二叉树先序遍历方法,将数组分为一个个有序数组;然后通过“治”将一个个有序数组通过合并merge方法组合成一个有序数组;1.“分”ve.原创 2021-11-06 22:06:56 · 646 阅读 · 2 评论 -
堆排序算法——C++
堆排序分为大顶堆排序和小顶堆排序,两者都是平均时间复杂度是O(nlogn),最坏时间复杂度是O(n^2),空间复杂度是O(1),是不稳定排序算法。大顶堆主要实现思想:1.初始化构建大顶堆void initMaxHeap(vector<int>& nums);2.将大顶堆的根(最大值)交换到数组最后面,然后将待排序数组长度减一后重新构建大根堆void buildMaxHeap(vector<int>& nums, int waitSortNod.原创 2021-10-30 00:12:34 · 322 阅读 · 0 评论 -
快速排序算法——C++
快速排序平均时间复杂度是O(nlogn),最坏时间复杂度是O(n^2),空间复杂度也是O(nlogn),是不稳定排序算法。主要实现思想:通过分区,首先选取基节点,基节点满足左边数据小于基节点,右边数据大于基节点;当完成一趟分区后,取得中间值,对左边数据同样进行分区满足“基节点左小右大”性质,对右边同样进行分区满足“基节点左小右大”性质,一直递归,直到左边数据哨兵指针大于等于右边哨兵指针即为结束条件。void Sorts::quick(vector<int>& nums, int原创 2021-10-27 23:57:30 · 411 阅读 · 0 评论 -
选择排序算法——C++
选择排序时间复杂度是O(nlogn),空间复杂度是O(1),是不稳定排序算法。主要实现思想就是通过双层循环,每次外层循环时,对内层进行遍历寻找最大值下表保存起来,内层循环结束后跟最后一个值交换。也就是每次遍历数组,然后将最大值交换到数组最后面。下面是遍历数组双层循环的套路代码:for (int j = nums.size() - 1; j > 0; --j) for (int i = 0; i < j; ++i)下面是实现选择排序算法代码Sorts.h#pragm原创 2021-08-11 22:39:03 · 594 阅读 · 4 评论 -
冒泡排序算法C++
冒泡排序算法比较简单,就是从左到右两两比较大小,比如升序排序,则把较大元素放到后面,第一轮结束后,开始第二轮比较排序;第二轮到第n-1个元素,一只到第n-1轮到比较最开始的两个元素则终止比较,下面实现代码:#include <iostream>#include <vector>using namespace std;class Sort {public: void bubble(vector<int>& nums) {原创 2021-07-28 23:07:06 · 787 阅读 · 0 评论 -
线性表——栈Stack的实现 C++
栈和队列是应用最多的数据结构之二,有数组实现和链表实现两种方式。当需要对容器做出限制,只允许一边插入和取出数据时,则需要用到栈。下面将总结数组实现的栈和阐述其原理。一、线性表——栈Stack1.1栈Stack定义栈是一种特殊的线性表,其插入(也称为入栈或压栈)和删除(也称为弹出或出栈)操作都在表的同一端进行;该插入和删除的端口称为栈顶(top),另一端称为栈底(bottom)。1.2栈的基本运算1.2.1基本运算(1) 初始化(构造一个空的栈)(2) 计算栈长度(栈中节点个数)(3) 插入节原创 2021-03-12 23:17:35 · 1839 阅读 · 2 评论 -
线性表——链表ChainList的实现 C++
本文主要总结常用的数据结构——线性表之链式描述,实现其基本的增删查改功能,不涉及完整功能,目的是为了熟悉常用数据结构属性和代码实现底层原理。顺序表结构有以下缺点:插入或删除节点时,需要移动大量数据如果表很大,有时难以分配连续存储空间,导致内存分配失败而无法存储而链表内存空间却可以不是连续的,所以链表恰好解决了顺序表只能申请连续存储空间的缺点。那么,链表是什么呢?接下来让我们学习一下什么是链表?一、线性表——链式描述ChainList1.1链表定义(链表数据结构的创建和调用(C++))链表原创 2021-03-07 01:58:08 · 2129 阅读 · 0 评论 -
线性表——顺序数组seqList的实现 C++
本文主要总结常用的数据结构——线性表之数组实现,实现基本运算功能,不涉及完整功能,目的是为了熟悉常用数据结构特性和代码实现底层原理。一、线性表——数组Array1.1线性表定义从逻辑上来看,线性表就是有n(n>=0)个数据元素a1,a2,…,an组成的有限序列。对于一个非空的线性表,其逻辑结构特征如下:有且仅有一个开始结点a1和一个直接后继节点a2,没有直接前驱节点,;有且仅有一个终止节点an和一个直接前驱节点a*(n-1)*,没有直接后继节点;其余的内部节点ai (2 <=原创 2021-02-28 23:24:22 · 1727 阅读 · 0 评论 -
删除字符串中第一个重复的 指定字符的左边所有字符 函数总结
本文主要总结一个删除字符串中第一个重复的指定字符的左边所有字符函数,简单来说,就是比如字符串“abcbefg”,比如我要删除第一个重复字符'b'左边所有字符,也就是要删除字符串“abcbefg”中的字符“ab”,剩下的字符是“cbefg”。该问题的解决方法,博主在leecode看到一个非常精妙的解法,代码如下:int left = 0;string s = {abcbdefg};un...原创 2020-02-05 23:36:51 · 989 阅读 · 0 评论 -
求字符串中不重复的最长子串的长度(C++,leecode)
求一个字符串中不重复的最长子串时,最简单的办法就是暴力破解法,另一种是巧妙使用指针来求解。暴力破解法虽然简单粗暴,但是效率太低,几乎不实用;后一种巧妙用指针法效率较大,但是需要对指针有较深理解。本文用代码实现的是指针法,暴力破解法有需要的可以自行根据下面思路编程。下面将分别讲解两种方法思路和指针法代码。1.1暴力破解法思路a1 先把字符串的所有子串全部求出,可以参考这篇博客:https:/...原创 2020-02-05 22:01:55 · 3514 阅读 · 0 评论 -
单链表加法总结(C++,leecode,整形int)
本文主要总结链表加法代码,全文分为两部分,为思路讲解和代码实现。1.1思路讲解链表的加法主要根据小学数学10进制进位方法来解。两个链表数据相加,主要是每个节点对应的数据相加,当有进位标志时,则在下一个节点把这个进位标志加上,即sum=val1+val2+carry。两个链表相加,和的链表长度有两种情况,第一种是等于两个加数链表的最长一个,另一种是比两个加数链表中最常的一个链表长度大一,...原创 2020-02-05 14:16:35 · 1178 阅读 · 0 评论 -
链表数据结构的创建和调用(C++)
在数据结构与算法中,链表是一个稍微有些难以理解的数据结构。本文主要总结链表的基本编程用法,通过创建一个链表和调用链表每个节点的数据代码,展示基本的链表数据结构用法。1.1原理讲解链表是在物理上可以是非连续的存储空间,由一片片存储区域组成,每个存储区域又被成为节点,每个节点又指向下一个节点,用一个链表头和链表尾串起来,所以被称为链表。链表的每个节点由两部组成,分别是数据区和指针。数据区存储需...原创 2020-02-04 23:24:43 · 2655 阅读 · 0 评论 -
两数之和2:输入有序数组(leecode)(c++)
在一个有序数组中,找出两个数,使得两数之和等于目标值。数组下标从1开始。输入: numbers = [5,6,7,8,9,10], target = 11输出: [1,2]解释: 5 与 6 之和等于目标值 11 。因此 index1 = 1, index2 = 2 。1.1解题思路有三种常见解法,一种是暴露和哈希表,可以参考博主写的这篇博客https://blog.csdn.ne...原创 2020-02-04 11:06:53 · 394 阅读 · 0 评论 -
在一个数组中找出两个数,这两个数之和为指定目标值,返回这两个数下标(leecode)(c++)
本文主要总结在一个数组中取出两个数,这两个数满足条件为:两数之和为制定目标值target,并且函数返回这两个数下表。示例:给定 nums = [5,6,7,8,9,10], target = 19因为 nums[4] + nums[5] = 9 + 10 = 19所以返回 [4, 5]1.1解题思路根据题意,可以看出这是一个组合问题,也就是高中数学常见的排列组合基本问题。...原创 2020-02-03 18:53:14 · 6108 阅读 · 0 评论 -
C++求字符串所有子串并顺序输出string::substr()
在Leecode做算法题时,经常遇到一些字符串的题目,这些题目有不少是有一种通用解法,也就是暴力解法。用穷举法列出所有可能的结果,然后根据附加条件进一步筛选符合条件的解。本文主要总结的是求出一个字符串中,所有子串,子串是稳定的,也就是说,相对原来的字符串位置顺序不变。下面是总结代码和思路。1.1求解思路比如求解一个字符串“abcdefg”的所有子串,也就是相当于高中的数学组合排列。可以看成...原创 2020-02-02 22:39:46 · 5043 阅读 · 1 评论 -
程序员必须掌握的核心算法(C++)
本文完全转载如下博客地址,转载目的仅仅只是交流学习,如果侵权,请联系我,我会及时删除和处理!转载原文地址:https://blog.csdn.net/m0_37907797/article/details/102661778 ...转载 2019-11-03 01:11:10 · 1439 阅读 · 0 评论 -
直接插入排序算法总结(C++代码、Qt)
直接插入算法是一种稳定的(排序前后相同元素相对位置保持不变)排序算法,空间复杂度是,最坏时间复杂度是。一般用在数组基本有序或者数据规模很小的时候非常高效。直接插入排序主要思想是将一个数组分为有序数组和无序数组,然后将无序数组依次插入有序数组中,插入的时候,从无序数组的左边第一个数开始,往有序数组的右边第一个数从右到左插入;当待插入数据小于插入数据时,则该有序数组该位起的右边所有数据,依次向右移动一...原创 2019-10-29 22:27:24 · 697 阅读 · 0 评论 -
大根堆排序算法(C++实现、Qt)
堆排序算法是一种选择排序,主要思想是选好一个非叶子节点子树,然后用该子树较大的孩子跟父节点比较,较大者跟父节点交换。如果交换后,孩子节点不满足大根堆排序,则交换依次后,用交换的孩子作为根节点,对该孩子进行大根堆排序,直到所有孩子节点全部满足大根堆排序,然后才继续往上一层节点继续比较排序;下图是对大根堆排序原理图文动态讲解,引用这篇博主(https://blog.csdn.net/LoveHYZ...原创 2019-10-28 23:54:40 · 1602 阅读 · 0 评论 -
快速排序算法总结C++
本文主要用C++总结快速排序算法原理和代码。1.1快速排序算法原理快速排序的时间复杂度最坏为,平均时间复杂度为,采用了分而治之思想,是不稳定算法(一趟排序后,数列中原来前后位置顺序不变)。具体实现原理如下:a1 从数列中任意选取一个数作为基准数(枢轴,pivot)a2 遍历数列,将小于基准数的数放在基准数左边,大于基准数的数放在基准数右边;a3 对左右区间数列重复a1——a2过...原创 2019-10-16 22:47:52 · 317 阅读 · 0 评论