• 首页
  • 搜索
  • 工具
  • 分类
  • 日志
  • 友链
  • 图片

It's Geek KingYoungy

KEEP CHALLENGE
C/C++Unix/Linux应用层程序设计

L4D2_server_manager开发心得

2025-08-03 浏览量 122 暂无评论

1.Windows,Linux的字符编码方式

  • Linux 系统:默认使用 UTF-8 编码 处理文本(包括命令输出、文件内容等),中文会被编码为多字节序列(如“中”对应 0xE4 0xB8 0xAD)。
  • Windows PowerShell(中文系统):默认使用 GBK 编码(CP936),中文对应不同的多字节序列(如“中”对应 0xD6 0xD0)。
  • 你的 Windows GUI 项目:基于 Win32 API,所有字符串(如 LPCWSTR、WCHAR)均采用 UTF-16 编码(双字节,“中”对应 0x4E2D),这是 Windows 原生的字符编码格式。

2.git的使用

1.推送之前必须要拉取远程仓库。这是为了不错过远程项目的最新变化。
2.Visual Studio打开过程中不能改梯子结点,否则接下来将无法推送。需要重启Visual Studio,若仍不行,要么启动powershell以命令行的形式使用Git。若仍旧不行,逐个使用不同的梯子结点(使用美国多能成功)。但提交(commit)一定要在visual studio中完成否则git commit .会把整个项目都暂存破坏了只上传源码的gitignore规则。在VS中提交完成后,使用git push origin master或git push origin master:master推送。

- 阅读全文 -
计算机学科基础理论

《Operating System Concepts(操作系统概念)》核心笔记

2025-07-24 浏览量 179 暂无评论

《Operating System Concepts(操作系统概念)》核心笔记

一、操作系统结构

1.人机交互

方式:GUI(图形用户界面)与命令解释程序。后者又称作外壳(shell)。

2.系统调用

2.1分类:Windows API(Windows系统)、POSIX API(POSIX系统)、java API(java虚拟机)。
2.2使用:程序员一般不直接使用系统调用,而是使用API。如C语言的libc。因为API使用方便,系统调用更注重细节。API函数库帮助我们调用系统调用。
2.3实现:以C语言的open()API为例,编译得到可执行文件,并运行。此时动态链接器会将glibc链接到该进程虚拟地址空间。运行到read代码段时glibc会向内核的系统调用接口传递系统调用号这一数字,并通过内核指定的寄存器传递参数。
2.4分类:进程控制、文件管理、设备管理、信息维护、通信、保护。

3.微内核

3.1功能:只提供调度、内存管理和进程通信。
3.2特点(对比宏内核):微内核非核心的内核功能由用户态的二进制程序实现。宏内核所有内核功能都由.ko内核文件实现。
3.3代表操作系统:Windows NT,QNX,Tru64 Unix。

4.混合系统

4.1功能:内核提供核心服务,如调度与内存管理,其他的功能由别的.ko内核模块实现,需要时动态加载,但不像微内核,这些内核模块像函数一样直接相互调用,因为共享地址空间。

5.系统启动

5.1传统Linux系统启动方式(BIOS+MBR):​​BIOS​​ 从磁盘LBA 0(0号扇区)加载512字节MBR(文件为boot.img)到内存0x7C00并执行。MBR引导代码​​(前446字节)加载GRUB第二阶段(core.img)到内存0x8000,跳转执行。core.img解析grub.cfg,若双系统则显示grub窗口,加载用户选择的Linux内核或Windows Boot Manager到内存。————链式加载
5.2现代Linux系统启动方式(UEFI+GPT):UEFI不读取MBR​​,而是从 ​​ESP分区(EFI System Partition)​​ 加载 .efi 文件(如 grubx64.efi)。.efi 文件直接解析grub.cfg文件。
5.3Windows系统启动:传统方式大差不差,都是链式加载。现代方式下Windows会在ESP分区建立Microsoft文件夹存放其efi文件。若为双系统,则UEFI会根据配置选择加载Windows的efi文件或是Linux的efi文件。

二、任务调度

注:不再区分进程、(内核)线程、任务。

1.调度算法

1.1调度器分类:
短期调度程序/CPU调度程序——选择进程(任务)上CPU。
长期调度程序/作业调度程序——选择进程上内存,控制内存中的进程数量。(Windows、Unix没有)
1.2调度算法评价指标:
吞吐量:单位时间完成任务的数量。
等待时间:进程在就绪队列等待的时间。多用平均值。
响应时间:用于交互式系统,提交请求到产生首次相应的时间。
1.3调度算法分类:
a.先到先服务(First-Come First-Served, FCFS)。
b.优先级调度:最短作业优先(Shortest-Job-First, SJF)/最短下次CPU执行(平均等待时间最少,最优)、抢占式最短作业优先(最短剩余时间优先):可能导致优先级低的进程饥饿,但可通过老化避免。
c.轮转调度:专门为分时系统设计。时间片过小会导致更频繁的上下文切换的时间浪费。时间片过大就不再是分时系统而是FCFS系统了。
d.多级队列调度:将就绪队列分为多个单独队列,每个队列有自己的调度算法。划分方法可以是前台与后台划分。队列与队列之间通常采用固定优先级抢占调度,如前台队列对后台队列绝对优先。进程无法中途更换队列。
c.多级反馈队列调度:同多级队列调度,但进程随时间会更换队列,这允许等待过长的进程被移到高优先级队列,防止饥饿。

2.线程竞争范围

1.分类:用户级线程通常与同一进程的其他线程竞争谁能上进程被调度执行,称为进程范围竞争(Process-Contention Scope, PCS),内核级线程与整个系统的内核级线程竞争上CPU,称为系统竞争范围(System-Contention Scope, SCS),所有系统都有SCS,采用一对一模型的系统,如Linux、Windows,只有SCS调度。

3.常见操作系统调度算法

a.Linux——完全公平调度程序(Completely Fair Scheduler, CFS):进程的优先级为0~139,其中分为两个范围。0~99用于实时任务,100~139用于普通任务。实时任务对于普通任务可抢占。实时任务之间根据优先级,低的可抢占高的。普通任务根据nice值映射到100~139的优先级。普通任务的优先级仅仅代表CPU时间分配的长短,不能抢占。
b.Windows——优先级多级反馈队列抢占调度算法:采用32级优先级,1~15级为可变类,16~31级为实时类,一个可变优先级的线程的每用完一个时间片便降低一个优先级等级但最终不低于优先级基值(可设置),当其等待的IO结束时其优先级会提升。

三、同步

- 阅读全文 -
C/C++Unix/Linux应用层程序设计

C++ STL中的栈与队列:核心原理与实战应用指南

2025-05-29 浏览量 161 暂无评论

C++ STL中的栈与队列:核心原理与实战应用指南

在C++标准模板库(STL)中,stack(栈)和queue(队列)是两个重要的容器适配器,它们通过封装底层容器(默认使用deque)实现了特定的数据操作逻辑。本文将深入探讨它们的设计原理、常用操作及典型应用场景,帮助开发者快速掌握其核心用法。


一、栈(stack):后进先出的数据管理
核心特性与初始化

栈遵循后进先出(LIFO)原则,仅允许在栈顶进行插入和删除操作。其底层通常基于deque或list容器实现。

include <stack>

std::stack<int> s;  // 默认基于deque的整型栈

常用操作及示例

方法         功能描述 示例代码

push(x) 将元素x压入栈顶 s.push(10);
pop() 移除栈顶元素(不返回值) s.pop();
top() 返回栈顶元素的引用(需非空检查) int val = s.top();
empty() 判断栈是否为空(返回布尔值) if (s.empty()) {...}
size() 返回栈中元素数量 int cnt = s.size();

操作示例:遍历栈并输出所有元素

std::stack<int> s;
s.push(1); s.push(2); s.push(3);
while (!s.empty()) {
    std::cout << s.top() << " ";  // 输出:3 2 1
    s.pop();

典型应用场景

括号匹配:通过栈结构检测表达式中的括号嵌套是否正确

深度优先搜索(DFS):递归算法中隐式使用栈管理访问路径

撤销操作:文本编辑器中按顺序记录操作步骤

二、队列(queue):先进先出的任务调度
核心特性与初始化

队列遵循先进先出(FIFO)原则,元素在队尾插入,队首删除。底层同样基于deque或list实现。

include <queue>

std::queue<std::string> q;  // 字符串队列

常用操作及示例

方法         功能描述 示例代码

push(x) 将元素x插入队尾 q.push("task1");
pop() 移除队首元素(不返回值) q.pop();
front() 返回队首元素的引用(需非空检查) auto task = q.front();
back() 返回队尾元素的引用 auto last = q.back();
empty() 判断队列是否空 if (q.empty()) {...}
size() 返回队列元素数量 int len = q.size();

操作示例:处理任务队列

std::queue<int> q;
q.push(10); q.push(20); q.push(30);
while (!q.empty()) {
    std::cout << q.front() << " ";  // 输出:10 20 30
    q.pop();

典型应用场景

广度优先搜索(BFS):按层次遍历树或图结构

消息队列:异步处理系统中的任务缓冲

打印任务调度:保证文档按提交顺序打印

三、进阶扩展:优先队列(priority_queue)
优先队列是队列的变种,元素按优先级排序(默认最大堆)。常用于任务调度系统:
include

// 小顶堆示例
std::priority_queue<int, std::vector, std::greater> pq;
pq.push(3); pq.push(1); pq.push(4);
pq.top(); // 返回1(当前最小元素)

- 阅读全文 -
计算机学科基础理论

算法——排序

2025-05-04 浏览量 163 暂无评论

一、插入排序

1.直接插入排序与折半插入排序。

  1.1步骤:
   (1)对于第i个元素,先用临时变量保存之,然后在1 ~ i-1的有序序列中找到其该插入的位置k。
   (2)将k到i-1的所有元素后移一位,导致k被腾出。
   (3)将临时变量保存的i号元素赋值到k位置。
  *对于折半插入排序,因为i前必有序,找插入位置可使用折半查找。注意mid与临时变量相等时(即序列有重复元素),让low = mid + 1而非直接结束,最后将low ~ i-1或high+1 ~ i-1的元素往后移动一位腾出位置供插入。k=low。这样做是为了保证稳定性。考虑abcccdec,最后一个c为待插入前面的元素,mid=4与临时变量匹配就认为找到了k的话,在5的位置还有一个c就会被移动,就不稳定。
  *对于直接插入排序,步骤(1)的找位置与步骤(2)同时进行。
  *时间复杂度为O(n^2)。空间复杂度为O(1)。稳定。

2.希尔排序/缩小增量排序

  2.1思想:
   以逐渐减小为1的增量(步长)划分子表,一个增量d可以把原序列化为d个子表,对每个子表插入排序即可。增量为1就是直接插入排序了。
  *时间复杂度不明。空间复杂度为O(1)。不稳定。

二、交换排序

1.冒泡排序

  *对于求冒泡的趟数的,把每一趟结束的序列写出来不要偷懒。最后千万别忘了得到一个排完序的序列之后实际上程序还要再跑一趟从而发现没有进行任何交换才会结束。
  *时间复杂度为O(n^2)。空间复杂度为O(1)。稳定。

2.快速排序

  *思想:移走首元素留下空位,比首元素(枢轴pivot)小的移到前面空位从而在后面产生空位,大的移到后面空位从而在前面产生空位,两者交替,最终空的就是存放首元素的位置。
  *画二叉排序树的心算方法:把序列写出来,把首元素(枢轴pivot)写到序列下面,序列与其下的pivot充当一个结点。左手手指为low指针,右手笔为high指针,分别指向序列首尾。先low不动,high从当前位置的前一位开始判断是否比pivot小,不是则写入到该结点右分支的最左,high往左移动并继续判断,直到找到并写入到该结点左分支的最右或high与low相等则表明该结点成功生成子结点了。若结束原因非后者,则此次是保持high不变,low从其后一位开始移动直到low指向的大于pivot从而写入到high的位置或low与high相等。两者如此交替重复几轮终会导致low=high。此时两个子结点就生成完毕。然后对两个子结点的序列进行同样的操作。(详见王道p351第10题)
  *时间复杂度:最好时树高logn,树的每一层low与high都对整个序列一个个的遍历,为n。故最好时间复杂度O(nlogn)。最坏树是单支树,O(n^2)。快速排序发生最好的情况的概率更大,故平均时间复杂度O(nlogn)。
  *空间复杂度:即同时处于栈段的函数栈的个数,即树的树高,因此最好O(logn)最坏O(n),平均O(logn)。
  *定下一个序列的枢轴最终所在的位置需要比较的次数就是该序列长度-1。因为所有的比较无非就是枢轴元素与其他所有元素的比较。

三、选择排序

1.简单选择排序

  *思想:每次从无序序列中选出最大/最小的元素交换到有序序列前/后一位。

2.堆排序

  *堆即顺序存储的,根与其两个孩子有大小关系的完全二叉树。若堆有n个元素,则非叶结点的数量为⌊n/2⌋个。
  *堆分为大根堆与小根堆。
  步骤:
  a.先将序列建堆。方法是序列前⌊n/2⌋个元素调用HeadAdjust函数。该函数针对传入其的根结点,暂存根结点并产生k与i双指针,其中k永远是i的双亲。在一个i每次乘2(指向其左孩子)的循环中,先比较左右孩子孰大孰小以确定i是否+1成为k的右孩子,在比较i与k孰大孰小决定是否让i移动到k的位置上,若无需移动则表明当前k结点为根的树符合堆的定义了,否则接下来k=i调整其子树成为堆。
  b.建立n-1次的循环。这里与选择排序一致,因为堆顶一定是最大/小的元素,省去了选择排序遍历的麻烦。但每次将堆顶元素交换到后面都要调用HeadAdjust函数调整前面。
  *建堆时间复杂度O(n),堆排序时间复杂度O(nlogn),总体O(nlogn),空间复杂度O(1)。不稳定。
  *堆的插入操作:新结点放序列末尾,然后向上调整。时间复杂度O(logn)。
  *堆的删除操作:删除结点,以序列末尾元素代替。然后向下调整。时间复杂度O(logn)。
  *题目若要求堆排序、堆插入或堆删除的比较次数,对每个结点,先比较其两个子结点的大小,选出有资格与该结点比较的子结点与该结点比较。子结点若不为叶结点则继续往下记录比较次数。
  *题目若要求堆排序、堆插入或堆删除的交换次数,对每个结点,若其子结点移动到该结点的位置就算“交换”,即使实际代码中子结点并没有被该结点赋值。

四、归并排序

  1.思想(以排成从小到大的序列为例):
  *全局建立一个辅助数组B,长度与序列长度相同。(因为首位弃用故长度为元素个数+1)
  *函数Merge:传入待排序数组A,以及low,high,mid。左半部分数组为A[low~mid],右半部分数组为A[mid+1~high],两个子数组都有序。将所有这些元素通通移动到B中同下标的位置。然后设置三指针i,j,k。i为B中左半部分数组的移动索引,j为B中右半部分数组的移动索引,k为A的移动索引。循环比较B[i]与B[j],谁小谁移到B[k](相等则先把左子数列中的移到A保证稳定性),A[i]移走i++,A[j]移走j++,k不管谁移走都要加1。最终因为i与j的任何一个出界退出循环。最后再将没有移动完的B的子数组移动到A剩余位置。
  *函数MergeSort:利用递归,递归结束条件是传入该层递归函数的low与high相等,否则产生变量mid=(low+high)/2,以low到mid调用他自己,再以mid+1到high调用他自己。最后调用Merge将low到high中的序列排有序。

2.排序趟数取决于树高,O(logn),每趟O(n),时间复杂度O(nlogn),空间复杂度O(n),稳定。

五、基数排序

  1.思想:从关键字本身的信息出发,设关键字为r进制,位数为d位,个数为n个。设置r个队列,将最低位,放进相应队列(分配),再将各个队列的关键字保持先后顺序的拿出来存进链表(收集),再到下一位直至最高位。从高位出发到低位亦可行。
  2.共d趟,每趟分配O(n),收集O(r),时间复杂度O(d(n+r)),空间复杂度O(r)。

- 阅读全文 -
  1. 1
  2. 2
  3. 3
  4. ...
  5. 10
  • 站点概览
author

40 日志
4 分类
Creative Commons
  • 热门文章
  • 热评文章
  • 随机文章
  • 在 Debian 服务器上部署 FileBrowser 并集成到现有博客路径
  • 高等数学重要定理总结
  • C语言原子量的使用
  • 高等数学重要定义整理
  • 高等数学刷题心得
  • 欢迎使用 Typecho
  • 对底层IO的深度总结
  • 数据结构——树
  • 库、链接与执行
  • shell作业控制的两个问题:组长叛变与SIGHUP信号
  • 欢迎使用 Typecho
  • IO多路复用与高性能IO编程接口详解
  • Unix Domain Socket 编程:字节流与数据报套接字详解
  • Internet Domain Socket 编程:字节流与数据报套接字详解
  • 实现安卓与类安卓系统的定位信息伪造

浏览量 : 15195

© 2025 It's Geek KingYoungy. Power By Typecho . Theme by Shiyi

浙ICP备2025160639号  |  浙公网安备33020502001222号

This is just a placeholder img.