- 博客(48)
- 收藏
- 关注
原创 快速排序 | C++|时间空间复杂度
快速排序(QuickSort)的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
2023-08-20 19:33:20
467
原创 Git的正确使用姿势与最佳实践:团队协作和版本控制的最佳实践
Git是一个版本控制系统,用于跟踪和管理软件开发项目中的代码变更。它可以追踪文件的修改、添加和删除,并记录这些变更的历史。Git可以帮助团队成员协同开发,并提供了一种有效的方式来处理并发编辑和代码合并。在这篇文章中,我们将介绍Git的正确使用姿势和最佳实践,以便更好地使用Git来管理代码进行团队协作。
2023-08-20 19:21:52
386
原创 Go语言进阶:函数、指针、错误处理
函数是基本的代码块,用于执行一个任务。Go 语言最少有个 main() 函数。你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
2023-08-20 16:14:26
521
原创 Go语言上手:复合数据类型
slice是变长序列,所以可以声明一个未指定大小的数组定义切片var 数组名字 []type//也可以简写为切片除了长度还有一个容量(capacity)的概念,可以在声明slice的时候同时指定长度和容量通过 s1 := arr[startIndex:endIndex] 可以创造新切片s1 ,且arr可以为数组,其余操作貌似和python的切片类似,不过go的切片更像一个变长数组或者说链表。Go支持append()函数用于向切片中追加值,支持copy()函数用于复制切片。
2023-08-20 16:07:01
737
原创 Go语言入门指南:基础语法和常用特性(下)
注意:如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明,例如:a := 20 就是不被允许的,编译器会提示错误 no new variables on left side of :=,但是 a = 20 是可以的,因为这是给相同的变量赋予一个新的值。Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:Go 语言变量名由。的声明语句,包一级的各种类型的声明语句的顺序无关紧要 (译注 : 函数内部的名字则必须先声明之后才能使用)。
2023-08-20 15:57:50
507
原创 Go语言入门指南:基础语法和常用特性解析(上)
Go是一种静态类型的编译语言,常常被称作是21世纪的C语言。Go语言是一个开源项目,可以免费获取编译器、库、配套工具的源代码,也是高性能服务器和应用程序的热门选择。Go语言可以运行在类UNIX系统——比如Linux、OpenBSD、Microsoft Windows等操作系统上。因为Go语言的特性,现很多互联网大厂公司都在使用,如字节跳动、Google、百度、美团等等。
2023-08-20 15:49:20
510
原创 多线程|线程同步和线程安全
线程有一套完整的与其有关的函数库调用,它们中的绝大多数函数名都以开头。为了使用这些函数库调用,我们必须定义宏,在程序中包含头文件pthread.h,并且在编译程序时需要用选项来链接线程库。-L指定库的存储位置-l指定库的名称并行:特殊的并发运行,同步运行,需要多个处理器并发:在一段时间内交替执行,单个处理器就可以进行注意:有多个处理器不一定是并行也可以是并发。
2023-08-16 21:19:25
128
原创 线程|线程的使用、四种实现方式
1.用户级线程开销小,用户空间就可以创建多个。缺点是:内核无法感知用户级多个线程的存在,把其当作只有一个线程,所以只会提供一个处理器。2.内核级线程相对于用户级开销稍微大一点,可以利用多个处理器。3.组合级线程Linux 实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux 把所有的线程都当做进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。
2023-08-16 21:08:22
575
原创 进程和线程的区别
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。每个进程都有自己独立的内存空间,一个进程中至少有一个或者多个线程,一个进程可以同时执行多个线程,多个线程共享资源。◼ 进程的切换开销大,线程的切换开销相对较小。
2023-08-16 20:57:23
110
原创 进程|详解~什么是进程 以及 进程创建原理和过程
进程是正在运行的程序。UNIX标准将进程定义为:其中运行着一个或者多个线程的地址空间和这些线程所需要的系统资源(分配给线程线程共享系统资源)。组成:进程由程序代码、数据、变量(占用着系统内存)、打开的文件(文件描述符)、环境组成。
2023-08-16 20:47:22
1287
原创 旋转链表:给你一个链表的头节点head,旋转链表,将链表每个节点向右移动k个位置
2.找到旋转后的尾节点 (正数第n-k%n) —>因为可能k≥n,则需要k%n 特别提醒:如果k是n的整数倍,则新链表与原链表相同,不需要旋转。给你一个链表的头节点head,旋转链表,将链表每个节点向右移动k个位置。输入:head = [1,2,3,4,5], k = 2。(这里可以将闭环看作一个钟表的旋转,头结点看作12点整)1.将链表构成一个环 —>首尾相连,即尾节点指向头结点。3.更改旋转后新的头结点,并进行切割环(断开首尾连接)输出:[4,5,1,2,3]
2023-08-08 16:13:46
499
原创 合并K个有序的链表
解释:链表数组如下:[ 1->4->5, 1->3->4, 2->6]将它们合并到一个有序链表中得到。输入:lists = [[1,4,5],[1,3,4],[2,6]]请将所有链表合并到一个升序链表中,返回合并后的链表。给定一个链表数组,每个链表都已经按升序排列。输出:[1,1,2,3,4,4,5,6]两两进行合并(二路归并法合并两个链表)输入:lists = []输出:[]
2023-07-30 22:55:10
166
原创 分割链表
我们只需维护两个链表 small和 large 即可,small 链表按顺序存储所有小于 x 的节点,large 链表按顺序存储所有大于等于 x 的节点。遍历完原链表后,我们只要将 small 链表尾节点指向 large 链表的头节点即能完成对链表的分隔。给你一个链表的头节点 `head` 和一个特定值 `x` ,请你对链表进行分隔,使得所有 小于 `x` 的节点都出现在 大于或等于 `x` 的节点之前。输入:head = [1,4,3,2,5,2], x = 3。输出:[1,2,2,4,3,5]
2023-07-30 22:52:30
122
原创 C++的作用域
3)进入到块里创建y,块结束则销毁y (块域是局部加锁的重要工具,有时候希望锁住函数一部分而不是锁住函数的全部,则加上一个块域,如进入块域加锁退出块域解锁)类的成员名字在其所在的类作用域内、或者派生类作用域内可见,或者通过 .运算符、->运算符、::限定符访问。其内部声明的名字的作用域从首次声明之处至该块的结束之处。const 修饰的变量只能在本文件中使用,而要想在其它文件中使用,则必须显示的加上extern。在类的定义体内可见的所有成员和方法(包括普通成员普通函数和静态成员静态函数)都属于类域。
2023-07-28 23:19:38
173
原创 系统是怎么知道全局变量、局部静态变量或者局部静态对象只能被构建一次?
2.在多线程中,线程函数funa和funb都在调用GetObject()函数创建objx,当funa在读objx的标记值时,值为0则创建objx,与此同时funb线程也在读objx的标记值,此时值还未改变也是0,则objx可能会被创建两次。而静态对象objx被创建两次带来的问题是,线程funb会把线程funa初始化objx的值覆盖掉。因为此标记值是系统维护的,我们无法用互斥量对这个标记值进行保护,但是可以将线程进行加锁,在funa执行的时候给线程加锁,执行完了之后解锁,再去执行线程funb。
2023-07-28 23:16:31
104
原创 懒汉模式线程不安全的解决方法
懒汉模式存在线程不安全,解决方法是:加互斥锁加锁后保证了线程安全,对象仅被创建了一次(obja和objb是同一个地址,Object构造函数只调用一次),线程funa设置的value值未被覆盖。运行结果如下。
2023-07-28 23:11:00
253
原创 单例模式——懒汉、饿汉
1.单例模式:单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性。(在内存中只会创建且仅创建一次对象的设计模式。)2.为什么要有单例模式?单例模式是为了保证程序的线程安全。什么是线程安全?在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。如何保证线程安全?给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。让线程也拥有资源,不用去共享进程中的资源。
2023-07-28 23:06:46
3886
原创 C++类中的this指针
静态成员函数不能定义成const常性:因为类中const修饰的是this指针,静态成员函数没有this指针全局函数也不能定义成const:全局函数也没有this指针。2.所有类对象公用成员函数方法,数据都是私有的,用this指针区分不同对象调用成员函数。总结:只有类的普通成员函数可以定义成const,核心在于看函数是否有this指针。友元函数也不能定义成const:友元函数也没有this指针。
2023-07-27 00:02:30
68
原创 static在C语言和C++中的区别 | 十分详细,一文彻底解决static
1)全局量被静态关键字修饰只在本文件中有效,仍存储在静态区,生命周期没变。2)函数被静态关键字修饰只在本文件中有效3)在函数中局部变量用静态关键字定义,生命周期存在于整个程序中,但变量只能在函数中访问,且此只能创建初始化一份4)static 修饰变量还有一特点,当变量未初始化时,默认初始化为 0。这是因为在静态存储区,所有内存都被默认置为 0,有时这一特点可减少工作量。
2023-07-26 23:59:32
391
原创 1.两数相加 | 数组、哈希表
使用一个新的集合map,map.key存放当前遍历过的元素值,map.value存放已经遍历过元素的下标。在原数组中顺序遍历查找map中是否存在target-nums[i]的值,如果不存在则将其nums[i]和他对应的下标i存入map中,如果存在,则找到结果,返回一个数组集合{map.value,i}。给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。但是,数组中同一个元素在答案里不能重复出现。
2023-07-26 23:47:41
64
原创 2.两数相加 | 链表
给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。迭代O(n)—>两链表的数字对应相加。
2023-07-26 23:45:14
200
原创 剑桥offer:重建二叉树——输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出的二叉树并输出它的头节点。2.在中序遍历中找到根节点的位置 k,则 k左边是左子树的中序遍历,右边是右子树的中序遍历;3.假设左子树的中序遍历的长度是 len,则在前序遍历中,根节点后面的 len个数,是左子树的前序遍历,剩下的数是右子树的前序遍历;4.有了左右子树的前序遍历和中序遍历,我们可以先递归创建出左右子树,然后再创建根节点;
2023-07-26 23:34:46
72
原创 剑桥offer:两个链表的第一个公共结点
1. 用两个指针 p,q 分别指向两个链表 headA,headB 的头结点,同时向后遍历。保证两个链表不完全相同,即两链表的头结点不相同。若没有公共结点,且都走到对方链表的尾部(即p=q=nullptr)2. 当指针到达链表末尾时,重新定位到另一个链表的头结点。2.都从头开始走,让较长的链表先走两个链表长度之差的步数。3.然后两链表一起走,相遇的结点即为第一个公共结点。p走的长度为a+c+b = q走的长度是b+c+a。p走的长度为a+b = q走的长度是b+a。输入两个链表,找出它们的第一个公共结点。
2023-07-26 23:29:17
183
原创 剑桥offer:复杂链表的复刻
在复杂链表中,每个结点除了有一个指针指向下一个结点外,还有一个额外的指针指向链表中的任意结点或者null。3.将插入的所有复制结点从原链表中拆分出来形成一个新链表,并将原链表进行还原。1.将每个结点n的后面插入一个复制了val和next的结点n'2.将每个结点n的random指针复制给每个n‘结点。函数结束后原链表要与输入时保持一致。请实现一个函数可以复制一个复杂链表。链表长度 [0,500]。
2023-07-22 20:57:26
64
原创 剑桥offer:合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。输入:1->3->5 , 2->4->5。输出:1->2->3->4->5->5。新建一个链表,将l1和l2归并在新链表中。链表长度 [0,500]。
2023-07-22 20:55:02
65
原创 剑桥offer:反转链表 | 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点
所以我们可以先递归处理 reverseList(head->next),这样我们可以将以head->next为头节点的链表进行翻转,我们令当前头结点的后继结点的next指针指向head,并将head->next指向空即可将当前新链表链表翻转。根据递归的思想,要想翻转1->2->3->null链表,需要先翻转2->3->null链表;要想翻转2->3->null链表,需要先翻转3->null链表。输入:1->2->3->4->5->NULL。输出:5->4->3->2->1->NULL。
2023-07-22 20:52:15
121
原创 剑桥offer:链表中环的入口结点
用两个指针fast,slow,分别从起点开始走,slow每次走一步,fast每次走两步。如果过程中 fast走到null,则说明不存在环。否则当fast和 slow相遇后,让 slow返回起点,fast待在原地不动,然后两个指针每次分别走一步,当相遇时,相遇点就是环的入口。注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。该算法的数学证明:----------有兴趣可以看看哦!给定一个链表,若其中包含环,则输出环的入口节点。若其中不包含环,则输出`null`。
2023-07-22 20:47:53
181
原创 剑桥offer:链表中倒数第k个节点
2.链表的倒数第 k个节点,相当于正数第 n−k+1个节点。所以第二次遍历到第 n−k+1个节点,就是我们要找的答案。注意当 k>n时要返回nullptr。(链表) O(n) 由于单链表不能索引到前驱节点,所以只能从前往后遍历。如果 k 大于链表长度,则返回 NULL;输入:链表:1->2->3->4->5 ,k=2。输入一个链表,输出该链表中倒数第 k 个结点。1.第一次遍历得到链表总长度 len;链表长度 [0,30]。
2023-07-22 20:42:58
57
原创 剑桥offer:删除链表中重复的节点
3.因为链表有序,即相同的数字在同一段内,然后从前往后扫描整个链表,每次扫描元素相同的一段,如果这段中的元素个数多于1个,则将整段元素直接删除。2.用两个指针,一个指向已经扫描过的段区间长为1的链表末尾,一个指向下一段的起始结点(循环找到下一个段长为1的结点)。在一个排序的链表中,存在重复的节点,请删除该链表中重复的节点,重复的节点不保留。链表有序,则将链表元素分段,相同元素在同一段区间,删除区间长大于1的。输入:1->2->3->3->4->4->5。输入:1->1->1->2->3。
2023-07-22 20:39:59
66
原创 剑桥offer:在O(1)时间删除链表结点
由于是单链表,我们不能找到前驱节点,所以我们不能按常规方法将该节点删除。我们可以换一种思路,将下一个节点的值复制到当前节点,然后将下一个节点删除即可。给定单向链表的一个节点指针,定义一个函数在O(1)时间删除该结点。删掉节点:第2个节点即6(头节点为第0个节点)假设链表一定存在,并且该节点一定不是尾节点。输入:链表 1->4->6->8。输出:新链表 1->4->8。链表长度 [1,500]。
2023-07-22 20:34:23
90
原创 剑桥offer:二叉树的下一个结点
1.如果当前节点有右孩子,则右子树中最左侧的节点就是当前节点的后继。2.如果当前节点没有右孩子,则需要沿着father域一直向左上方找,若当前结点是father的左孩子子,则该节点的father就是当前结点的后继,如左图F的后继结点是H;若当前结点是father的右孩子,就需要一直沿着father域向上找,找到树的拐点处的father即为该结点的后继,如右图E的后继为A。假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。则应返回值等于3的节点。
2023-07-22 20:28:53
45
原创 剑桥offer:用两个栈实现队列
2.pop(),此时我们需要弹出最先进入栈的元素,也就是栈底元素。我们可以先将所有元素从主栈中弹出,压入辅助栈中。则辅助栈的栈顶元素就是我们要弹出的元素,将其弹出即可。然后再将辅助栈中的元素全部弹出,压入主栈中。3.peek(),可以用和pop()操作类似的方式,得到最先压入栈的元素。* pop() – 将队头的元素弹出,并返回该元素;1.push(x),我们直接将x插入主栈中即可。4.empty(),直接判断主栈是否为空即可。* push(x) – 将元素x插到队尾;* peek() – 返回队头元素;
2023-07-22 20:05:46
50
原创 剑桥offer面试题:从尾到头打印链表|题目——输入一个链表的头节点,从尾到头反过来打印出每个结点的值。(打印链表的值只是一个可读操作,最好不要修改链表的结构)
遍历是从头到尾访问结点中的value,而打印却是从尾到头。也就是说第一个遍历到的结点需要最后一个输出,最后一个遍历到的结点需要第一个输出,以此看来可以用到栈的特性“先进后出”。
2023-05-10 17:28:35
74
原创 剑桥offer面试题:不修改数组找出重复的数字|给定一个长度为 n+1 的数组`nums`,数组中所有的数均在 1∼n 的范围内,其中 n≥1。请找出数组中任意一个重复的数,但不能修改输入的数组。
给定一个长度为 n+1 的数组`nums`,数组中所有的数均在 1∼n 的范围内,其中 n≥1。请找出数组中任意一个重复的数,但不能修改输入的数组。1≤n≤1000。
2023-05-10 17:22:24
110
原创 剑桥offer面试题:找出数组中重复数字|两种算法|时间复杂度
优化空间为O(1):将每个数放到对应的位置上,即让 nums[i] = i。如果nums[i]的值不是i,则将其值交换到正确的下标位置上,交换过程中如果遇到重复则返回该nums[i]。
2023-05-10 16:50:07
138
原创 数据结构C【直接插入排序和希尔排序】算法|代码|时间空间复杂度|稳定性~一章帮你搞清楚
直接插入排序:将一个关键字(记录)插入到已经排好序的有序序列中,从而得到一个新的、关键字(记录)增1的有序序列。希尔排序:将相距某个 ”增量“ 的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果时基本有序而不是局部有序。
2023-04-25 15:09:32
442
原创 Linux常用命令大全|VMware虚拟机网络连接|终端配置
常用的基础命令pwd:显示当前所在位置的绝对路径cd 路径:切换当前工作位置,cd后的参数表示要切换到的位置(可使用绝对路径/相对路径)cd . 退回到当前位置cd .. 退回到上一层cd - 切换到上一次所在位置,在两个位置之间来回切换cd ~ 直接进入到当前用户的家目录ls:默认显示当前位置当前目录下的内容ls 路径:显示指定目录下的内容ls -l(简写ll)ls -a(显示隐藏文件)ls显示非隐藏文件,按照文件名顺序排列ls -a(--all的缩写
2023-04-08 16:52:52
10114
原创 Linux简介|发行版本|与Widows的区别
1991年 芬兰赫尔辛基大学的学生Linus Torvalds推出的操作系统,而后由更多开发者进行修改和完善。Linux是类Unix系统,并不是Unix。
2023-04-08 15:50:59
280
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人