王道考研操作系统同步与互斥(王道大题详解)(二)

简介: 王道考研操作系统同步与互斥(王道大题详解)(二)

五、经典同步问题


1.生产者-消费者问题

问题描述

一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才能把消息放入缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。


问题分析

生产者消费者互斥访问缓冲区

生产者消费者是相互协作关系(个人理解:前文所说的同步问题是单方向的,即先。。。再。。。,而这里的互相协作代表了同步是双向的,即有时要先等生产者生产后消费者才能消费,有时要等消费者消费后生产者才能生产。而这里的有时就由信号量决定。因为有两个同步关系,所以在解决同步问题时需要有两个信号量。)

信号量 m u t e x mutexmutex 作为互斥信号量,初值为一

信号量 f u l l fullfull 表示缓冲区有物品(满)的数量,初值为零,用来解决 生 产 者 → 消 费 者 生产者 \to 消费者生产者→消费者 的同步问题。信号量为零时,必须生产者先生产商品,消费者才能消费。

信号量 e m p t y emptyempty 表示缓冲区没有物品(空)的数量,初值为 n nn,用来解决 消 费 者 → 生 产 者 消费者 \to 生产者消费者→生产者 的同步问题,信号量为零时,必须消费者先消费商品,生产者才能生产

代码展示

semaphore mutex = 1;
semaphore full = 0;
semaphore empty = n;
producer()
{
    while (1)
    {
        produce an item in nextp;
        P(empty);
        P(mutex);
        add nextp to buffer;
        V(mutex);
        V(full);
    }
}
consumer()
{
    while (1)
    {
        P(full);
        P(mutex);
        remove an item from buffer;
        V(mutex);
        V(empty);
        consume the item;
    }
}


若生产者进程先 P ( m u t e x ) P(mutex)P(mutex),然后执行 P ( e m p t y ) P(empty)P(empty),消费者先执行 P ( m u t e x ) P(mutex)P(mutex),然后执行 P ( f u l l ) P(full)P(full),可不可以?


不行,假设缓冲区已满,先运行生产者进程,它先互斥加锁,然后执行 P ( e m p t y ) P(empty)P(empty) 被阻塞,这是去运行消费者进程,执行 P ( m u t e x ) P(mutex)P(mutex),但此时锁在生产者进程,因此消费者进程也被阻塞,导致无休止的等待。

再看一个较为复杂的生产者消费者问题


问题描述

桌子上有一个盘子,每次只能向其中放入ー个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等吃盘子中的橘子,女儿专等吃盘子中的苹果。只有盘子为空时,爸爸或妈妈才可向盘子中放一个水果:仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出。


问题分析

信号量 p l a t e plateplate 作为同步信号量,初值为一,用来解决 盘 子 变 空 事 件 → 放 水 果 事 件 盘子变空事件 \to 放水果事件盘子变空事件→放水果事件,也就是先盘子为空,才能放水果。但其实盘子为空事件可以由女儿或者儿子引起,所以进程同步不能从单一进程角度考虑,而是由系列事件的先后顺序角度出发,加以分析!

信号量 a p p l e appleapple 表示缓冲区苹果的数量,初值为零,用来解决 爸 爸 → 女 儿 爸爸 \to 女儿爸爸→女儿 的同步问题,信号量为零时,必须爸爸先放苹果,女儿才能消费

信号量 o r a n g e orangeorange 表示缓冲区橘子的数量,初值为零,用来解决 妈 妈 → 儿 子 妈妈 \to 儿子妈妈→儿子 的同步问题,信号量为零时,必须妈妈先放橘子,儿子才能消费

🚫 王道书里plate是互斥信号量,但其实完全不是这样的!按照我之前的推论和在王道代码中的实际位置和效果,也可以看出它实际上是一个同步信号量。**先盘子为空,才能放水果。**王道书中我觉得有点误人子弟了。


后来看了咸鱼学长的视频,发现他讲的是正确的,也介绍了为什么可以不写互斥。可能写书的不是他吧。还是建议2倍速把咸鱼视频过一遍再看书,效率奇高。



上图是加了互斥信号量的情况。那么为什么可以去掉?


原因在于本题缓冲区大小为1,在任何时刻,三个同步信号量最多只有一个值为一。因此在任何时刻,最多只有一个进程的 P PP 操作不会被阻塞,并顺利进入临界区。


问:那缓冲区大小为1,一定不用设置互斥信号量?


答:只是有可能不需要设置,还是要具体问题具体分析。


代码展示

semaphore plate = 1;
semaphore apple = 0;
semaphore orange = 0;
dad()
{
    while (1)
    {
        prepare an apple;
        P(plate);
        put the apple on the plate;
        V(apple);
    }
}
mom()
{
    while (1)
    {
        prepare an orange;
        P(plate);
        put the orange on the plate;
        V(orange);
    }
}
son()
{
    while (1)
    {
        P(orange);
        take an orange from the plate;
        V(plate);
        eat the orange;
    }
}
daughter()
{
    while (1)
    {
        P(apple);
        take an apple from the plate;
        V(plate);
        eat the apple;
    }
}


这里的互斥锁夹的实际上是两个进程,因为爸爸和女儿,妈妈和儿子必须连续的执行。所以个人理解(不一定对)为爸爸和女儿,妈妈和儿子这两个流程互斥


2.读者-写者问题

问题描述

有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。


问题分析

题意:任一写者在完成写操作之前不允许其他读者或写者工作


写者要与读者互斥,但同时也要与其他写者互斥

题意:允许多个读者可以同时对文件执行读操作


这说明仅有一个互斥信号量不能解决问题,因为一个互斥信号量只能让每次只有一个进程访问临界资源。这导致多个读者之间也互斥,不符合题意。造成这的原因是每次读者进程都会进行一次 P PP 操作,那么为了使多个读者可以同时对文件执行读操作,我只有在第一个读者进程访问时上锁,在最后一个读者进程离开时解锁。所以需要一个计数器判断当前在读文件的读者数量。

信号量设置


信号量 r w rwrw 为互斥信号量,初值为一,保证读者和写者的互斥访问

信号量 m u t e x mutexmutex 为互斥信号量,初值为一,保证计数器在更新时的互斥访问

代码展示

int count = 0;
semaphore rw = 1;
semaphore mutex = 1;
writer()
{
    while (1)
    {
        P(rw);
        writing;
        V(rw);
    }
}
reader()
{
    while (1)
    {
        P(mutex);
        if (count == 0)
        {
            P(rw);
        }
        count++;
        V(mutex);
        reading;
        P(mutex);
        count--;
        if (count == 0)
        {
            V(rw);
        }
        V(mutex);
    }
}


上面算法种,读者进程是优先的,也就是说只要有一个读者进程活跃,随后而来的读者进程都可以访问文件,而写者进程却被长时间阻塞,存在长时间饿死的情况。


代码优化

如果希望写优先,当读进程正在读文件时,有一个写进程请求,就应该阻止后续的读进程请求,等到当前访问文件的读进程们执行完毕,立刻让等待的写进程执行。在无写进程执行的情况下,才放先前排队的读进程们执行。


增加一个互斥信号量 w ww,初值为一,用于保证“写优先”

int count = 0;
semaphore rw = 1;
semaphore mutex = 1;
semaphore w = 1;
writer()
{
    while (1)
    {
        P(w);
        P(rw);
        writing;
        V(rw);
        V(w);
    }
}
reader()
{
    while (1)
    {
        P(w);
        P(mutex);
        if (count == 0)
        {
            P(rw);
        }
        count++;
        V(mutex);
        V(w);
        reading;
        P(mutex);
        count--;
        if (count == 0)
        {
            V(rw);
        }
        V(mutex);
    }
}


注意 w 信号量的位置。为什么怎么加?我们可以推一下看看


问:读 者 1 → 写 者 1 → 读 者 2

答:读者1正在读文件时,写者1来了,会被 r w  信号量阻塞,读者2来了,会被 w 信号量阻塞。在读者1读完撤离后,$ V(rw)$ 保证了写者1紧随其后运行,写者1撤离后,V ( w )保证读者2紧随其后运行

问:写 者 1 → 读 者 1 → 写 者 2

答:写者1正在写文件,读者1来了,会被 w ww 信号量阻塞,读者2来了,也会被 w 信号量阻塞。信号量的阻塞队列保证了先来先服务,所以读者1会先执行。这就导致并不是“写进程优先”,实际上是读写公平

注意:写进程优先是相对而言,实际上可以叫做读写公平法。


3.哲学家进餐问题

问题描述

一张圆桌边上坐着5名哲学家,每两名哲学家之间的桌上摆一根筷子,两根筷子中间是一碗米饭。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。若筷子已在他人手上,则需要等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,进餐完毕后,放下筷子继续思考。


问题分析

每名哲学家与左右邻居对在其中间的筷子是互斥访问


问题的关键就在于如何拿到左右筷子而不造成死锁


方法一:同时拿左右两根筷子


方法二:对每个哲学家的动作制定规则,避免死锁现象的发生


信号量设置:


信号量数组 c h o p s t i c k [ 5 ] = { 1 , 1 , 1 , 1 , 1 } ,用于对五个筷子互斥访问。哲学家按顺序编号为 0 ∼ 4,哲学家 i ii 左边筷子的编号为 i ii,哲学家右边筷子的编号为 ( i + 1 ) % 5

代码展示

有问题的代码

semaphore chopstick[5] = {1, 1, 1, 1, 1};
Pi()
{
    do
    {
        P(chopstick[i]);
        P(chopstick[(i + 1) % 5]);
        eat;
        V(chopstick[i]);
        V(chopstick[(i + 1) % 5]);
        think;
    } while (1);
}


存在问题:5名哲学家同时想吃饭并都拿起左边的筷子。筷子都被拿完,这时他们想拿右边的筷子,就全被阻塞,产生死锁。


问:如何防止死锁的发生?


答:施加一些限制条件


方法一:最多允许四位哲学家同时进餐,这样可以保证至少有一个哲学家是可以拿到左右筷子的


方法二:要求奇数号哲学家先拿左边的筷子,偶数号哲学家先拿右边的筷子。这样可以保证相邻的奇偶号哲学家都想吃饭时,只会有其中一个可以拿起第一只筷子,另一个直接阻塞。这样避免了占有一只后再等待另一只的情况。


方法三:仅当一名哲学家左右两边筷子都可用时,才允许哲学家拿起筷子(王道书上原话,但其实并不准确)。准确说法为:各个哲学家拿筷子这件事是互斥的,这样就保证一个哲学家拿筷子拿到一半时被阻塞,也不会有别的哲学家继续尝试拿筷子。这样的话,当正在吃饭的哲学家放下筷子后,被阻塞的哲学家就可以获得等待的筷子了。


采用方法三,代码如下:

semaphore chopstick[5] = {1, 1, 1, 1, 1};
semaphore mutex = 1;
Pi()
{
    do
    {
        P(mutex);
        P(chopstick[i]);
        P(chopstick[(i + 1) % 5]);
        V(mutex);
        eat;
        V(chopstick[i]);
        V(chopstick[(i + 1) % 5]);
        think;
    } while (1);
}


大部分练习题和真题用消费者-生产者模型或读者-写者问题就能解决,但对于哲学家进餐问题和吸烟者问题仍然要熟悉。考研复习的关键在于反复多次和全面,“偷工减料”是要吃亏的。


4.吸烟者问题

问题描述

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌上,如此重复(让三个抽烟者轮流地抽烟)。


问题分析

信号量设置


信号量 o f f e r 1 表示烟草和纸组合的资源数,初值为0,用来描述 供 应 者 提 供 烟 草 和 纸 组 合 → 一 号 吸 烟 者 卷 烟 供应者提供烟草和纸组合 \to 一号吸烟者卷烟供应者提供烟草和纸组合→一号吸烟者卷烟 的同步问题

信号量 o f f e r 2 表示烟草和胶水组合的资源数,初值为0,用来描述 供 应 者 提 供 烟 草 和 胶 水 组 合 → 二 号 吸 烟 者 卷 烟 供应者提供烟草和胶水组合 \to 二号吸烟者卷烟供应者提供烟草和胶水组合→二号吸烟者卷烟 的同步问题

信号量 o f f e r 3 表示纸和胶水组合的资源数,初值为0,用来描述 供 应 者 提 供 纸 和 胶 水 组 合 → 三 号 吸 烟 者 卷 烟 供应者提供纸和胶水组合 \to 三号吸烟者卷烟供应者提供纸和胶水组合→三号吸烟者卷烟 的同步问题

信号量 f i n i s h  作为同步信号量,初值为0,用来描述 抽 掉 烟 事 件 → 放 材 料 事 件 抽掉烟事件 \to 放材料事件抽掉烟事件→放材料事件,我这里说事件,就是为了强调引起抽掉烟这一事件的主体不是一个进程,而是吸烟者1,2,3都有可能引发这一事件。

代码展示

int num = 0;
semaphore offer1 = 0;
semaphore offer2 = 0;
semaphore offer3 = 0;
semaphore finish = 0;
process P1()
{
    while (1)
    {
        num++;
        num = num % 3;
        任意两种材料放在桌上;
        if (num == 0)
        {
            V(offer1);
        }
        else if (num == 1)
        {
            V(offer2);
        }
        else
        {
            V(offer3);
        }
        P(finish);
    }
}
process P2()
{
    while (1)
    {
        P(offer1);
        卷烟抽;
        V(finish);
    }
}
process P3()
{
    while (1)
    {
        P(offer2);
        卷烟抽;
        V(finish);
    }
}
process P4()
{
    while (1)
    {
        P(offer3);
        卷烟抽;
        V(finish);
    }
}


下图是王道书中供应者的相关代码



我觉得是有问题的。我的改动地方就是“任意两种材料放在桌子上”这句话的位置。按照王道的逻辑,我 V完后被切到对应的那个吸烟者进程,那个进程就可以进行卷烟吸烟的操作。但按照逻辑来说,你材料实际上并没有放到缓冲区,这是于事实相矛盾的!


还有要强调的是这里供应者的 P V  顺序可不可以换。我认为是可以的,当然前提是改 f i n i s h 初值为1。


六、王道习题详解


大题1

题目


答案

当共享资源用共享数据结构表示时,资源管理程序可用对该数据结构进行操作的一组过程来表示,如资源的请求和释放过程request和release。。把这样一组相关的数据结构和过程一并归为管程。Hansan为管程所下的定义是:“一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据。”由定义可知,管程由三部分组成:


1)局部于管程的共享变量说明。


2)该数据结构进行操作的一组过程。


3)对局部于管程的数据设置初始值的语句;此外,还需为该管程赋予一个名字。


管程的引入是为了解决临界区分散所带来的管理和控制问题。在没有管程之前,对临界区的访问分散在各个进程之中,不易发现和纠正分散在用户程序中的不正确使用,V操作等问题。管程将这些分散在各进程中的临界区集中起来,并加以控制和管理,管程一次只允许一个进程进入管程内,从而既便于系统管理共享资源,又能保证互斥。


大题2

题目


答案

1)是互斥关系,同一本书只能被一名学生借阅,或任何时刻只能有一名学生借阅一本书。


2)是互斥关系,篮球是互斥资源,只可被一个队伍获得。


3)是同步关系,一个工序完成后开始下一个工序。


4)是同步关系,生产商品后才能消费。


大题3

题目


答案

信号量设置


互斥信号量 m u t e x ,初值为1

同步信号量 o d d,初值为0,表示奇数的个数。生产者先放一个奇数,P 2  才能取

同步信号量 e v e n,初值为0,表示偶数的个数。生产者先放一个偶数,P 3才能取

同步信号量 e m p t y ,初值为 n,表示缓冲区没有物品(空)的数量。先消费者取出东西,生产者才能再放东西

semaphore mutex = 1;
semaphore odd = 0;
semaphore even = 0;
semaphore empty = n;
P1()
{
    while (1)
    {
        x = produce();
        P(empty);
        P(mutex);
        put(x);
        V(mutex);
        if (x % 2)
        {
            V(odd);
        }
        else
        {
            V(even);
        }
    }
}
P2()
{
    while (1)
    {
        P(odd);
        P(mutex);
        getodd();
        V(mutex);
        V(empty);
        countodd();
    }
}
P3()
{
    while (1)
    {
        P(even);
        P(mutex);
        geteven();
        V(mutex);
        V(empty);
        counteven();
    }
}


大题4

题目



答案

不能,x xx 作为临界资源没有被互斥访问


直接上答案



大题5

题目


答案

这题还是挺坑的,没考虑全,因为甚至在if语句里x都有切换进程,x值改变的可能性!


z的值:− 2 , 1 , 2 , 3 , 5 , 7

c的值:9 , 25 , 81


大题6

题目


答案

对于条件二显然需要同步信号量。这个要求如何转化?假设信号量 S a

,实际上就是要把这个不等式的临界值转化成信号量 S a

 为零时的含义。题目中,A产品和B产品数量差为 M MM 时,我的信号量 S a

 应该值为零。当我的 S a

 表示什么的时候,满足条件?自然而然推出 S a

 表示A产品还可以放的产品数量(按理来说A和B的数量差应该由A和B一起控制,这里我只用A表示的原因是只有在A产品生产时才有可能会到达临界情况)。


信号量设置


互斥信号量 m u t e x,初值为1

同步信号量 S a

,初值为 M − 1  ,表示产品A还可以放的数量

同步信号量 S b  

,初值为 N − 1  ,表示产品B还可以放的数量

semaphore mutex = 1;
semaphore Sa = M - 1;
semaphore Sb = N - 1;
process_A()
{
    while (1)
    {
        P(Sa);
        P(mutex);
        A产品入库;
        V(mutex);
        V(Sb);
    }
}
process_B()
{
    while (1)
    {
        P(Sb);
        P(mutex);
        B产品入库;
        V(mutex);
        V(Sa);
    }
}


大题7

题目


答案

信号量设置


同步信号量 t a k e n u m takenumtakenum,初值为 0 00,表示已经取号的顾客数量

同步信号量 c a l l n u m callnumcallnum,初值为 0 00,表示空闲可以叫号的销售员数量

semaphore takenum = 0;
semaphore callnum = 0;
salesman()
{
    while (1)
    {      
        P(takemun);
      叫号;
      推销面包;
      V(callnum); 
    }
}
consumer()
{
    进店;
    取号;
    V(takenum);
    P(callnum);
    被服务;
}


大题8

题目


答案

信号量设置


同步信号量 e m p t y ,初值为 500,表示还可以容纳多少人

互斥信号量 m u t e x ,初值为1,可使出入口一次仅一人通过

semaphore empty = 500;
semaphore mutex = 1;
cobegin
参观者进程i:
{
    ... 
    P(empty);
    P(mutex);
    进门;
    V(mutex);
    参观;
    P(mutex);
    出门;
    V(mutex);
    V(empty);
    ...
}
coend


大题9

题目


答案

信号量设置


互斥信号量 m u t e x 1,初值为一,表示互斥访问 F 1

互斥信号量 m u t e x 2 ,初值为一,表示互斥访问 F 2

同步信号量 e m p t y 1,初值为10,表示 F 1

 空闲的容量

同步信号量 e m p t y 2 ,初值为10,表示 F 2

 空闲的容量

同步信号量 f u l l 1 ,初值为0,表示 F 1

 已用的容量

同步信号量 f u l l 2 ,初值为0,表示 F 2

 已用的容量

semaphore mutex1 = 1;
semaphore mutex2 = 1;
semaphore empty1 = 10;
semaphore empty2 = 10;
semaphore full1 = 0;
semaphore full2 = 0;
producer_A()
{
    while (1)
    {
        生产零件A;
        P(empty1);
        P(mutex1);
        放到货架F1;
        V(mutex1);
        V(full1);
    }
}
producer_B()
{
    while (1)
    {
        生产零件B;
        P(empty2);
        P(mutex2);
        放到货架F2;
        V(mutex2);
        V(full2);
    }
}
consumer()
{
    while (1)
    {
        P(full1);
        P(mutex1);
        取零件A;
        V(mutex1);
        V(empty1);
        P(full2);
        P(mutex2);
        取零件B;
        V(mutex2);
        V(empty2);
        组装产品;
    }
}


大题10

题目


答案

信号量设置


互斥信号量 v a t ,互斥访问水缸

互斥信号量 w e l l ,互斥访问水井

互斥信号量 p a i l ,初值为3,互斥的访问水桶

同步信号量 e m p t y ,初值为10,表示缸剩余可以容纳的水的桶数

同步信号量 f u l l ,初值为0,表示缸中已有的水的桶数

semaphore vat = 1;
semaphore well = 1;
semaphore pail = 3;
semaphore empty = 10;
semaphore full = 0;
old()
{
    while (1)
    {
        P(full);
        P(pail);
        P(vat);
        打水;
        V(vat);
        V(empty);
        喝水;
        V(pail);
    }
}
young()
{
    while (1)
    {
        P(empty);
        P(pail);
        P(well);
        从井里打水;
        V(well);
        P(vat);
        倒水;
        V(vat);
        V(full);
        V(pail);
    }
}


易错点


要先看水缸容量后再决定是否拿起水桶,如果顺序颠倒,会引发死锁。


大题11

题目


答案

理一下关系,数据abc依次输入,所以要保证先p1再p2最后p3的顺序。


同步信号量 S 2 ,初值为零,用来维护先p1后p2的顺序

同步信号量 S 3 ,初值为零,用来维护先p2后p3的顺序

王道答案的 S 1  其实是没有必要的,因为3个进程中后2个进程都会被阻塞,只有P1可以运行。互斥信号量也不需要,因为在同一时刻只会有一个设备正常运行未被阻塞。

p1需要p2中的数据b


同步信号量 S b SbSb,初值为零,用来维护先b被p2取出后 x = a + b x=a+bx=a+b 才能执行这一顺序

p1需要等y和z都计算出后才能通过打印机打印


同步信号量 S y ,初值为零,用来维护先y计算出后p1通过打印机打印的先后顺序

同步信号量 S z ,初值为零,用来维护先z计算出后p1通过打印机打印的先后顺序

semaphore S2 = 0;
semaphore S3 = 0;
semaphore Sb = 0;
semaphore Sy = 0;
semaphore Sz = 0;
p1()
{
    读取数据a;
    V(S2);
    P(Sb);
    x = a + b;
    P(Sy);
    P(Sz);
    打印机打印;
}
p2()
{
    P(S2);
    读取数据b;
    V(Sb);
    y = a * b;
    V(S3);
    V(Sy);
}
p3()
{
    P(S3);
    读取数据c;
    z = y + c - a;
    V(Sz);
}


发现写出来和王道答案不一样,我又推了一下,感觉自己的也没问题



我是在 y = a ∗ b 这一计算结束后才允许p3唤醒,这就保证了p3运行时y的值已有。而王道是先允许p3允许读取数据c,后等待 S y同步信号量。区别就在是否可以先读取数据c上,但题目中并未对数据c不是临界资源,所以何使读取无所谓。然后衍生一下,发现其实 S y  可以不需要,王道是让p1等待 S y 和 S z  两个信号量,但按照我的逻辑,已经保证了y和z的先后顺序,所以不需要 S y 。当然王道的逻辑肯定更加严谨,我也不保证我的理解对,纯粹突发奇想。

目录
相关文章
|
25天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
25天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
25天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
25天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
25天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
25天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
25天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
25天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构的基本概念;算法的基本概念、特性以及时间复杂度、空间复杂度等举例说明;【含常见的报错问题及其对应的解决方法】
|
25天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
3月前
|
安全
操作系统中的同步和监视器经典问题
【8月更文挑战第23天】
34 0
下一篇
无影云桌面