Njay的linux内核学习笔记1

comsol 多物理场仿真流程-以开关柜为例 1、主要方法 在SolidWorks中对于开关柜的内部与外部结构进行建模,生成能够导入软件计算的3D模型。将SolidWorks中的模型导入comsol软件中,设置参数进行多物理场耦合仿真。 1、具体步骤 删除高压开关柜中对其内部电磁环境无较大影响的结构,如低压测量柜、断路器内部结构等。 导入模型:将厂家提供的3D模型转化为solidworks结构模型。 修复模型:修复已转化模型中转化错误的部分、修复已转化模型中非实体部分、修复已转化模型中重叠实体部分 化简模型:去除过于... 阅读详情
  1.操作系统内核模式:

       1) 整体式的单内核模式,代码结构紧凑,执行速度快,层次结构性不强。

       2) 层次式的微内核模式。

     0.11版本的内核采用第一种模式。

 

   2.linux内核系统体系结构:

       linux内核主要由5个模块构成:进程控制模块,内存管理模块,文件系统模块,进程间通信模块和网络接口模块。这几个模块的相互关系如下图,虚线和虚线框表示在该版本中还未实现的:

       内核模块结构

    可以看到所有的模块都与进程调度有关,它们都需要依靠进程调度程序来挂起(暂停)或重新运行它们的进程。

    下图是内核结构图:

内核结构图

  3.中断机制:

         该版本是针对80X86 PC,采用两片8259A中断控制器实现管理15级中断向量IRQ0-IRQ15。在新版本的linux中,它已经支持多种不同ic硬件平台,而且对于一般的应用程序开发人员这部分可以不必过多的去研究,对于嵌入式开发人员来说,现在绝大多数的应用与嵌入式领域的IC都基本上有移植好的代码可供参考,我们只需要根据自己的硬件平台做一些修改就让linux跑起来。如果想深入了解X86的中断机制可以看看微机原理之类的书籍。

        对于linux内核,中断信号分为两类:硬件中断和软件中断(异常),每个中断有0-255之间的数来标识。对于Intel,int0-in31(0x00-0x1f)是作为软件中断,也称之为异常,因为这些中断的产生是在CPU执行指令时检测到而产生的,分为故障(fault)和陷阱(traps)两类。中断int32-int255(0x20-0xff)可以由用户自己定义。int32-int47对应硬件中断请求信号IRQ0-IRQ15。并把程序编程发出系统调用(system_call)中断设置为int28(0x80)。

   4.系统定时:

        1) 我们人需要脉搏维持生命,操作系统一样需要脉搏来作为系统的时钟节拍,称之为一个系统滴答。

        2) linux 0.11内核中,每隔10ms就发出一个时钟中断(IRQ0)信号。

        3) 每个滴答就会调用一次时钟中断处理程序timer_interrrupt,该处理程序主要通过jiffies变量来累计系统自启动以来经过的时钟滴答数。每发生一次中断该值就增1。

       4) do_timer()函数根据CPL判断当前进程运行在内核态还是用户态,并相应的将内核态或用户态的时间统计值stime或utime增1。

       5) do_timer()判断当前进程的时间片是否用完(<=0),如果用完则调用调度程序schedule切换到其他进程。

       6) 在内核态工作的进程在被中断时,do_timer会立即退出。这样的处理方式决定了linux系统在内核态运行时不被调度程序切换。内核态程序是不可抢占的,但处于用户态程序中运行时则是可以被抢占的。

  5.linux进程控制:

      1) linux 0.11版本,系统最多可以有64个进程存在,不过在新版内核中好象可以有4090g个(有待查阅)。

      2) 第一个进程是“手工”创建的。其余的都是进程使用系统调用fork函数创建。

      3) 每个进程中的代码和数据部分分别对应一个执行文件中的代码段,数据段。 

      4) linux系统中,一个进程可以在内核态(kernel mode)或用户态下执行。linux内核堆栈和用户堆栈是分开的。用户堆栈用于在用户态下临时保存调用函数的参数,局部变量等。内核堆栈则含有内核程序执行函数调用的信息。

 5.1 任务数据结构:

      1) 内核程序通过进程表对进程进行管理,每个进程在进程表中占有一项,它是一个task_struct任务结构指针。有的书上称进程控制块PCB(process control block)或进程描述符PD(process discriptor)。结构体如下:

struct task_struct {
/* these are hardcoded - don't touch */
 long state; /* -1 unrunnable, 0 runnable, >0 stopped */
 long counter;
 long priority;
 long signal;
 struct sigaction sigaction[32];
 long blocked; /* bitmap of masked signals */
/* various fields */
 int exit_code;
 unsigned long start_code,end_code,end_data,brk,start_stack;
 long pid,father,pgrp,session,leader;
 unsigned short uid,euid,suid;
 unsigned short gid,egid,sgid;
 long alarm;
 long utime,stime,cutime,cstime,start_time;
 unsigned short used_math;
/* file system info */
 int tty;  /* -1 if no tty, so it must be signed */
 unsigned short umask;
 struct m_inode * pwd;
 struct m_inode * root;
 struct m_inode * executable;
 unsigned long close_on_exec;
 struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
 struct desc_struct ldt[3];
/* tss for this task */
 struct tss_struct tss;
};

   2) 当一个进程在执行时,CPU的所有寄存器中的值,进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换(switch)至另一个进程时,需要保存当前进程的的所有状态,即上下文,以便在再次执行该进程时进行恢复。

 5.2 进程运行状态:

   1) 运行状态(TASK_RUNNING)。

   2) 可中断睡眠状态(TASK_INTERRUPTIBLE)。当系统产生了一个中断或者释放了进程正在等待的资源,或者进程收到一个信号,都可以唤醒进程转换到就绪状态(运行状态)。

   3) 不可中断睡眠状态(TASK_UNINTERRUPTIBLE)。处于该状态的进程只能被wake_up()函数明确唤醒时才能进入就绪状态。

   4) 暂停状态(TASK_STOPPED)。当进程收到信号SIGSTOP,SIGTSTP,SIGTTIN或SIGTTOU时就会进入暂停状态。发送SIGCONT就会让进程进入运行状态。该版本中未实现。

   5) 僵死状态(TASK_ZOMBIE)。当该进程已停止运行,但其父进程还没有询问其状态时,则称该进程处于僵死状态。

   6) 只有当进程从“内核运行态”转移到“睡眠状态”时,内核才会进行进程切换。

   7) 在内核态下运行的进程不能被其他进程抢占,而且一个进程不能改变另一个进程的状态。

    8) 为了避免进程切换时造成内核数据错误,内核在执行代码时会禁止一切中断。 

 5.3 进程初始化:

    1) 在boot目录下的汇编代码即引导程序将内核从磁盘上加载到内存中,并让系统在保护模式下运行,之后便进入系统初始化程序init/main.c,该程序代码如下:

void main(void)  /* This really IS void, no error here. */
{   /* The startup routine assumes (well, ...) this */
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
  ROOT_DEV = ORIG_ROOT_DEV;
  drive_info = DRIVE_INFO;
 memory_end = (1<<20) + (EXT_MEM_K<<10);
 memory_end &= 0xfffff000;
 if (memory_end > 16*1024*1024)
  memory_end = 16*1024*1024;
 if (memory_end > 12*1024*1024)
  buffer_memory_end = 4*1024*1024;
 else if (memory_end > 6*1024*1024)
  buffer_memory_end = 2*1024*1024;
 else
  buffer_memory_end = 1*1024*1024;
 main_memory_start = buffer_memory_end;
#ifdef RAMDISK
 main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
 mem_init(main_memory_start,memory_end);
 trap_init();
 blk_dev_init();
 chr_dev_init();
 tty_init();
 time_init();
 sched_init();
 buffer_init(buffer_memory_end);
 hd_init();
 floppy_init();
 sti();
 move_to_user_mode();
 if (!fork()) {  /* we count on this going ok */
  init();
 }

   2) 从代码中可以看出,mem_init之前都是对系统物理内存的初始化。之后便是对系统的中断(trap_init),块设备(blk_dev_init),字符设备(chr_dev_init),进程管理(sched_init),硬盘初始化(hd_init),软盘初始化(floppy_init)等,然后开中断sti。

   3) move_to_user_mode()将系统“手工”从内核态(特权级0)移动到用户态(特权级3)的任务0中运行。内核的初始化代码也即是任务0的代码,只是在移动到任务0之前系统正以内核态特权级0运行,在移动之后便继续执行原来的代码指令流。

  4) 调用fork函数创建新的进程时,需要复制任务0的任务数据结构,包括用户堆栈指针,因此要求在任务0的用户态堆栈在创建新的进程1前保持“干净”状态。

 

 5.4 创建新进程:

  1) linux创建新的进程都是通过调用fork函数实现的,所有进程都是通过复制进程0得到的,都是进程0的子进程。

  2) fork函数代码如下:

   _sys_fork:
 call _find_empty_process
 testl %eax,%eax
 js 1f
 push %gs
 pushl %esi
 pushl %edi
 pushl %ebp
 pushl %eax
 call _copy_process
 addl $20,%esp
1: ret

   其中的find_empty_process,copy_process在fork.c中实现。

  3) 为了防止这个未建立完的新进程被调度器执行,会在请求页内存后将进程状态设置为TASK_UNINTTERUPTIBLE,在做一系列任务堆栈数据后,最后再将进程状态设置成可运行状态并返回新进程号。

 5.5 进程调度:

  1) linux进程是抢占式的,被抢占的进程仍然处于TASK_RUNNING状态,只是暂时不被CPU执行。

  2) 进程的抢占发生在进程处于用户态执行阶段,在内核态执行时是不能被抢占的。

  3) linux 0.11中采用基于优先级排队的调度策略。

  4) 调度程序:schedule函数首先扫描任务数组,通过比较每个就绪态(TASK_RUNNING)任务的运行时间来确定当前哪个进程运行的时间最少。哪个的值最大就表示那个进程运行的时间不长,于是就选中该进程,并使用任务切换函数切换至该进程。

  5) 每个任务的需要运行的时间片值counter = counter/2 + priority(优先权值)。

  6) 如果没有任何进程可运行,系统就会选择进程0运行,进程0调度pause()把自己置为可中断睡眠状态并再次调用schedule(),其实schedule()并不在意进程0当前的状态,只要系统空闲就调度进程0。

  7) 任务切换:任务的切换主要就是通过宏定义的汇编程序switch_to实现,主要就是对当前任务的任务状态段TSS和新任务的任务状态段进行保存和恢复。原理如下图:

任务切换

 5.6 进程中止:

   1) 当一个进程结束了运行或在半途中终止了运行,那么内核就需要释放该进程所占有的系统资源。

   2) 当一个用户程序调用exit()系统调用后,就会执行内核函数d0_exit(),并做一系列的资源释放工作,再最后并调用schedule函数去执行其他进程。

   3) 在进程终止时,它的任务数据结构仍然保留着,因为其父进程还需要使用其中的信息。

   4) 在子进程执行期间,父进程会使用wait()或waitpid()函数等待其子进程的结束。当等待的子进程被终止并处于僵死状态时,父进程就会把子进程运行所使用的时间累加到自己的进程中,最终释放已经终止的子进程任务数据结构所占用的内存页面,并置空子进程在任务数组中占用的指针项。

 6. linux内核对内存的使用方法:

   1) linux 0.11中,内存被划分为如下几块:

 

   2) 在intel CPU中,提供了两种内存管理(变换)系统:内存分段系统(Segmentation System)和分页系统(Paging System)。分页是可选的。linux同时采用了这两种管理机制。

   3) linux 0.11中三种地址概念:a.程序(进程)的逻辑地址。b.CPU的线性地址。c.实际物理地址。a与b一起便映射到实际的物理地址C。

   4) 虚拟内存:在linux 0.11内核中,给每个程序(进程)都划分了总容量为64MB的虚拟内存空间,程序的逻辑地址范围为0x0000000到0x4000000。

  5) 虚拟地址空间分配图:

 

  6) 内存分页管理原理:将主内存区域划分成4096字节为一页内存页面,程序申请使用内存时,就以内存页为单位进行分配。

  7) CPU可以提供多达4G的线性地址空间,对于linux 0.11内核,系统设置全局描述表GDT中的段描述符项数最大为256,其中2项空闲,2项系统使用,每个进程使用两项,因此系统最多可以容纳(256-4)/2 + 1=127个任务,虚拟地址范围是((256-4)/2)*64MB约等于8G。

  8) linux 0.11中人工定义最多NR_TASKS=64任务,每个进程虚拟地址范围是64M,并且各个进程的虚拟地址起始位置是(任务号-1)*64MB。因此所使用的虚拟地址空间范围是64MB*64=4G。

  9) 线性地址空间使用示意图:

 

  7.linux系统中堆栈的使用方法:

   1) linux 0.11中共使用四种堆栈:a.系统初始化时使用的临时堆栈;b.供内核程序自己使用的堆栈(内核堆栈),只有一个,位于系统地址空间固定位置,也是任务0的用户态堆栈;c.每个任务通过系统调用,执行内核程序时使用的堆栈,称为内核堆栈;d.任务在用户态执行的堆栈,位于任务地址空间的末端。

  7.1 初始化阶段:

   1) 代码调用:bootsect.s->setup.s->head.s(进入内核保护模式)。

   2) 进入保护模式时的内核使用的堆栈示意图:

 

  3) 在main.c中,在执行move_user_mode()之前,系统一直使用上述堆栈。而在执行过move_user_mode()之后,main.c的代码被“切换”成任务0中执行。在调用fork函数后,main中的init函数是在任务1中执行,并使用任务1的堆栈,而main本身则在被“切换”成为任务0后,仍然使用上述内核程序自己的堆栈作为任务0的用户态堆栈。

 7.2 任务的堆栈:

   1) 每个任务有两个堆栈:内核态堆栈,很小(4096-任务数据结构)字节,大约3KB;用户态堆栈,可以在64MB中延伸;

   2) 在用户态运行时:

      a.每个任务(除任务0)都有自己的64MB空间。

      b.当一个任务被创建时,它的用户态堆栈指针被设置在其地址空间的末端,从 线性地址空间使用示意图中可以看出。

      c.其内核态堆栈则被设置成位于其任务数据结构所在页面的末段,从上面的堆栈示意图可以看出,应用程序在用户态一直使用该堆栈。

      d.由于linux使用写复制功能(Copy on Write),因此在进程创建后,若该进程及其父进程没有使用堆栈,则两者共享同一堆栈对应的物理内存页面。

    3) 在内核态运行时:

      a.从上面的堆栈示意图可以看出,每个任务及其自己的内核堆栈,与每个任务的任务数据结构(task_struct)放在同一内存页面。

      b.fork函数在调用copy_process时,设置任务数据结构p->tss.esp0 = PAGE_SIZE + (long) p;
 p->tss.ss0 = 0x10;其中p是任务的数据结构指针,tss段是task_struct中的一个字段,值得注意的是该任务的内核态堆栈值tss.ss0也被设置成0x10(内核数据段)。tss.esp0是指向保存task_struct结构页面的末端。

      c.进程的内核态堆栈图如下:

      d.每当任务执行内核程序而需要使用其内核时,CPU就会利用TSS结构把它的内核态堆栈设置成由这两个值构成。在任务切换时,老任务的内核堆栈指针(esp0)不会被保存。对CPU来讲,这两个值是只读的,因此每当一个任务进入内核态执行时,其内核态堆栈总是空的。

 7.3 任务内核态堆栈与用户态堆栈之间的切换:

   1) 任务调用系统调用时就会进入内核,执行内核代码。此是内核代码就会使用该任务的内核态堆栈进行操作。切换过程中会涉及堆栈状态保存与恢复,如下图:

 

  8.linux内核源代码的目录结构:

 

 

From: http://blog.youkuaiyun.com/Njay/archive/2007/05/17/1612848.aspx

2026年运维工程师常见面试选择题 这篇文章总结了30道Linux运维面试常见问题及解析,涵盖基础命令、系统监控、故障排查、数据库、缓存、容器编排等多个方面。主要内容包括: 基础命令使用:如df查看磁盘、free查看内存、top监控进程等 系统监控与故障排查:负载判断、端口检查、进程管理等 中间件相关:Nginx状态码、MySQL主从复制、Redis缓存问题 容器技术:Docker优势、Kubernetes作用 运维理念:高可用、监控告警、发布策略、备份容灾 工作原则:故障处理优先级、运维工程师核心能力 文章不仅提供标准答案,还解析了各命令的 阅读详情

相关推荐

程序化广告行业(23/89):深度剖析广告效果评估指标

大家好,我一直希望能和大家一起在技术领域不断探索、共同进步。在之前的文章中,我们了解了程序化广告中腾讯的业务布局和广告效果评估的基础概念,今天让我们进一步深入剖析广告效果评估的各项指标,这对理解程序化广告的运作机制至关重要

yyy173611的博客 4865

Linux内核驱动学习(五)KThread学习总结

文章目录简介例程运行结果参考 简介 使用内核线程需要包含头文件#include &lt;linux/kthread.h&gt;,下面整理了一下常用的api接口,如下表格所示; 函数 功能 struct task_struct * kthread_create(threadfn, data, namefmt, arg...) 创建一个线程 struct task_struct *...

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 6212

Java开发者必看:Apache PDFBox实现PDF数字签名完整指南(附源码)

本文为Java开发者提供了使用Apache PDFBox实现PDF数字签名的完整指南。详细介绍了从环境配置、核心原理到完整代码实现的全过程,涵盖证书管理、签名位置计算、性能优化及实际应用案例,并附有可直接复用的源码,帮助开发者高效集成PDF数字签名功能。

o1p2q3r的博客 340

【数据结构】基于比较的排序算法 - 交换排序

本文介绍交换排序中的冒泡排序与快速排序。冒泡排序通过相邻元素比较交换,实现升序,时间复杂度最坏为O(N²),空间复杂度O(1),稳定且适合小规模有序数据。快速排序采用分治思想,以基准值划分区间,平均时间复杂度O(N log N),空间复杂度O(log N),但不稳定,实际应用中性能优异,可通过随机基准、小区间优化等提升效率。

careathers的博客 362

智能车竞赛飞檐走壁组赛道制作全攻略:从电磁线铺设到立体元素搭建

本文提供了智能车竞赛飞檐走壁组赛道制作的完整指南。从电磁线选材、电流控制与精准铺设等基础入手,详细解析了垂直墙面、圆筒、跷跷板等核心立体元素的构建技巧与过渡处理。重点分享了确保赛道稳定、符合规则且便于调试的实战经验,帮助参赛队伍搭建可靠的立体赛道,为车模算法调试奠定坚实基础。

weixin_29292535的博客 1284

玩转RecyclerView | 实现子视图叠加 | 3D画廊效果 | 高级动效 | Android 3D坐标系介绍

之前写的一篇文章展示了RecyclerView实现的画廊效果,适用于专辑/图片/列表浏览效果。本篇文章阐述如何基于RecyclerView实现如下图所示的3D画廊效果。以下效果的重点在于实现子视图的图层叠加,滑动过程中的3D旋转效果较为简单。(1)无3D旋转效果图片(1)带3D旋转效果图片。

qq_38237224的博客 8155

【数据结构-5】单链表的实现

单链表,具体来说是单向的、不带头的、不循环的链表。链表由一个一个节点组成,每个节点分为数据域和指针域,数据域存放数据,指针域存放下一节点的地址。这样,就可以根据指针域中的地址找到下一个节点,节点就串起来了构成了单链表。

weixin_44218929的博客 200

Nordic nRF52832实战:手把手教你搭建智能手环BLE通信框架(附完整代码)

本文详细介绍了如何使用Nordic nRF52832芯片搭建智能手环的BLE通信框架,涵盖芯片优势、协议栈初始化、低功耗广播策略及健康数据服务实现。通过完整代码示例和架构设计,帮助开发者快速掌握蓝牙低功耗通信技术,适用于可穿戴设备开发。

weixin_29192141的博客 247

pandas 深度入门:从数据结构到一份真实销售报表

本文系统讲解Pandas核心应用,从三分钟安装到完整月度报表生成,涵盖数据读取、清洗、筛选、分组聚合、表连接、透视表与时间序列等13个关键环节。强调“先看数据再动手”,掌握Series/DataFrame/Index结构本质,熟练运用loc/iloc、merge校验、agg/transform区别,通过真实案例实现高效报表自动化,告别手动Excel操作。最后提供性能优化与高频报错解决方案,助力读者快速上手,真正实现“写二十行代码,跑三秒出结果”。

信息安全领域优质创作者|操作系统领域专家 299

把 LLM 编排能力塞进 ABAP 系统里,ZLLM 仓库的工程价值与 SAP 落地场景

ZLLM项目将LLM应用开发中的常见工程问题引入ABAP原生环境,为SAP系统提供AI工作流构建能力。它类似ABAP版的LangChain,支持Chain组合、Prompt模板、状态传递等核心功能,强调纯ABAP实现、延迟执行以及与ABAP数据结构的深度集成。项目包含工厂类、LLM客户端、负载均衡器等模块,特别设计了能处理ABAP内表和结构的模板引擎,使业务数据可直接用于Prompt生成。通过Step和Flow机制支持复杂业务过程编排,并采用延迟执行和并行处理优化批量任务性能。该项目为ABAP开发者提供了在

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 61

CMOS图像传感器——工作原理

CMOS图像传感器的曝光与读出

沧海一升的博客 9460

C# 数据结构和特殊类型

.NET Core(现称.NET)提供丰富数据结构,优化性能与开发效率。日常开发首选List<T>和Dictionary<TKey,TValue>;高性能场景推荐Span<T>与Memory<T>减少内存分配;并发环境使用ConcurrentDictionary等线程安全集合;避免非泛型集合如ArrayList。

cccloveforever的博客 695

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【数据结构】堆(Heap):堆的实现、建堆与堆排序

堆是一种特殊的完全二叉树,分为大堆(父节点≥孩子)和小堆(父节点≤孩子),可快速获取最值。堆通常用数组存储,通过下标计算父子关系。核心操作为向上调整(插入时)和向下调整(删除或建堆时),时间复杂度均为O(log N)。建堆可采用从后往前的向下调整法,整体复杂度为O(N)。基于堆的堆排序通过反复提取最大值实现升序排列,总时间复杂度为O(N log N),空间复杂度O(1),是高效稳定的排序算法。

2501_93577780的博客 351

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

数据结构的基本概念和算法的初步认识

本文系统阐述数据结构与算法的基础概念,涵盖数据、数据元素、数据对象的层次关系,数据结构的三要素(逻辑结构、存储结构、数据运算),以及抽象数据类型。重点解析算法的特性与设计要求,并深入讲解时间复杂度分析的核心——大O表示法,通过“只保留最高阶项、忽略常数系数、取最坏情况”三大原则,结合实例剖析O(1)、O(n)等常见时间复杂度,揭示算法效率的本质评估方法。

ACH_YYX的博客 193

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Redis 数据结构、单线程架构与 String 字符串详解

Redis采用单线程架构,通过事件循环(Event Loop)高效处理I/O事件,避免阻塞。其核心优势在于内存操作快、无上下文切换开销。数据结构支持多种内部编码(如ziplist、quicklist),自动根据场景优化存储与性能。字符串类型是基础且灵活,可存文本、数字或二进制数据,最大512MB,支持原子操作。命令如SET、GET、MGET、MSET等实现高效读写,适用于缓存、计数、会话管理等场景。

2303_77004089的博客 357

笔记-论数据结构3(算法分析-时间复杂度)

i <= n;s = 0;次数1234ti1248?i2^02^12^22^32^t-1在遍历的过程中,2^t-1次方的增长率肯定大于n,可得出结论2^t-1 > n那么,为了得出t和n的关系,我们可以运用对数关系:log2为底2^t-1 > log2为底n消掉log2为底2t-1 > log2为底nt > log2为底n+1于是可以得出。

fish_zzzz的博客 235

J1939 DM1 报文数据结构详解:单帧、BAM、CMDT 逐字节拆解与 DTC 跨包问题

1. 一条报文,两套字节结构 DM1 装的是灯具状态加一串 DTC,而串的长度决定哪一种字节结构上线。 8 字节以内是一帧 :两个灯具字节,之后每 DTC 四字节,末尾补齐。超过 8 字节就变成 的一帧 TP.CM 声明

废柴程序员-熊熊的博客 120

Vue3 低代码移动表单设计器实战(二):缩放画布下的拖拽系统与树状级联数据结构

本文深入剖析Vue3低代码表单设计器在缩放画布下的拖拽失效问题,揭示SortableJS在CSS Transform下坐标崩溃的数学根源。通过自研独立视觉克隆壳层与逆向几何补偿算法,实现精准拖拽;采用扁平数据存储+运行时树状计算结构,解决级联依赖与深克隆难题,确保逻辑一致性与性能优化,为复杂低代码系统提供可复用的工程范式。

NanChen的博客 347

排序算法深度笔记(上):比较类排序的思想演进与代码实现

与。本文聚焦前者 —— 也就是通过元素间两两比较来确定相对顺序的排序算法,从最朴素的 O (n²) 基础排序,到工业级主流的 O (nlogn) 进阶排序,逐层拆解设计思想、带注释的代码实现与边界细节。当我们理解了比较排序的性能边界,也就自然引出了非比较排序的存在意义。所有代码均遵循统一的实现规范:入口函数前置空数组与单元素边界校验,基于数组原地修改,主函数附带可直接运行的测试用例,与练习代码风格完全对齐。

2401_87069538的博客 631

CF2283F[数据结构]

首先考虑一种暴力解法,当我们建好i之前的图后,当我们添加i的时候,区间[li,ri]中的点都会向i建边,但是这些点中,如果有某两个顶点l,r,满足l<r,那么l就可以通过r间接到达i,因此可以删除l到i的边;初始时我们令所有点放入set中,然后对于每一个i的处理,我们将集合中仍在[l,r]的范围的点弹出,并且将f设置为i,这样我们就得到了所有点的最小跳板;对于每个区间[l,r] 我们要计算这下下标中的f(v)中大于r的数目有多少个;我们令f(v)表示顶点v可到达的最小的顶点;

蒟蒻 159

笔记-论数据结构2

typedef 数据类型 别名return 0;typedef也经常用在结构体上:每次声明结构体变量都要写struct关键字,很麻烦,而且逻辑上也很难受,typedef可以解决这个问题。int x;int y;p.x = 5;p.y = 10;return 0;而利用typedef解决有两种解法:typedef struct 结构体名数据类型 变量名;数据类型 变量名;……}别名;数据类型 变量名;数据类型 变量名;……}别名;实际的运用int x;

fish_zzzz的博客 114

【数据结构-3】算法美学之降复杂度

在while循环的循环体内,首先用临时变量保存最后一个位置的数据,再通过for循环把所有元素往后移动一位,最后把tmp中保存的值放到下标为0的位置上去。方法二的思路是:创建新数组,让原数组中后k个数据移动到新数组中前面的位置,让原数组中前numsSize-k个数据移动到新数组中后面的位置,这。这段代码的思路是:三次逆置,第一次逆置前numsSize-k个数据,第二次逆置后k个数据,最后整体逆置。这篇博文分享一道解法不一的算法题,求解过程的目的在于降低算法的时间复杂度,题源力扣。,属于空间换时间的操作。

weixin_44218929的博客 89

【数据结构】树和二叉树(下):讲透四种遍历、递归返回值与经典题

🔥 星光编译者📚 学习专栏:《C/C++ 成长笔记》《Linux 实践手册》《数据结构与算法》🌄 向云端飞扬,编译属于自己的代码星河。☕ 写在开篇你好,这里是星光编译者。这里记录我在C/C++、Linux、数据结构与算法学习中遇到的真实问题、亲手验证过的代码,以及那些容易被忽略的实现细节。比起简单罗列结论,我更愿意从问题出发,把一个知识点的来由讲清楚,把“为什么会这样”和“应该怎样解决”说明白,让每一次踩坑都沉淀成可以复用的经验。如果这篇记录能帮你少绕一点路。

星光编译者的技术博客,专注 C/C++、Linux、数据结构与算法。 453

成为全栈·基础补充·数据库迁移与事务:数据结构怎样安全演进

数据库升级为什么不能只执行一条 ALTER TABLE?本文区分结构迁移、事务和业务数据搬迁,介绍版本化迁移、expand/contract、真实数据库方言验证、事务边界与外部资源补偿。结合 PostgreSQL、MySQL、SQLite 的差异和一次 13 张业务表的离线导入演练,说明空库升级、备份、dry-run、关系核验及回退准备应如何形成一条可审阅的迁移流程。

FungLeo's Blog 463

【数据结构-2】顺序表的实现

线性表是一种数据结构,它分为逻辑结构和物理结构,在逻辑结构上线性表是呈线性的,数据是是连续存储的;在物理结构(物理空间)上,线性表不一定是连续存储的。线性表的实现,主要分为数组和链式结构。顺序表是线性表的一种实现方式,顺序表在逻辑结构和物理结构上都是连续的。顺序表的底层实现是数组。

weixin_44218929的博客 211

数据结构(2)

不同点顺序表链表(单链表)存储空间上物理上一定连续逻辑上连续,但物理上不一定连续随机访问支持:O(1)不支持:O(N)任意位置插入或删除元素可能需要搬移元素,效率低 O(N)只需修改指针指向插入动态顺序表,空间不够时需要扩容和空间浪费没有容量的概念,按需申请释放,不存在空间浪费应用场景元素高效存储 + 频繁访问任意位置高效插入和删除。

likexuec的博客 155
上一篇: 关于面向对象与面向过程(面向结构)的区分
下一篇: UNIX/Linux编程相关工具和资源
AlphaJay
博客等级 码龄22年 19粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值