编程艺术之源:深入了解设计模式和设计原则

深入了解设计模式和设计原则

  • 一、认识设计模式
    • 1.1、设计模式是什么?
    • 1.2、设计模式是怎么来的?
    • 1.3、设计模式解决了什么问题?
  • 二、设计模式的基础
    • 2.1、面向对象思想
    • 2.2、设计原则
  • 三、如何学习设计模式
    • 3.1、明确目的
    • 3.2、学习步骤
  • 总结

一、认识设计模式

设计模式总共有23种,首先呢,我们来对设计模式有一个大致的了解,带着这几个问题来思考一下:

  • 设计模式是什么?
  • 设计模式是怎么来的?
  • 设计模式解决了什么问题好?
  • 怎么学习设计模式?或者说设计模式的基础是什么?
  • 如何学习设计模式?

1.1、设计模式是什么?

那什么是设计模式呢?看设计模式的定义:设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案

从这个定义可以看出,设计模式有很多的限定词,比如“特定”、“重复特定”等。那说明什么问题呢?说明设计模式在使用的时候它有很多的局限性。所以,学习设计模式一定要切入它的一个本质,也就是它解决一个什么问题,然后再去使用它。当我们不清楚这个设计模式解决什么问题的时候,不要轻易的去使用设计模式,所以设计模式是适用的好。

设计模式的定义换一句都能够听懂的话,就是设计模式是解决软件开发过程中一些问题的固定套路,解决问题的固定套路。因此,不要过度的去封装或者去使用设计模式,除非我们已经确定了这个设计模式,就是明确了我们的这个具体需求的变化方向;而且这个变化方向的这个点呢,经常的出现,反复的出现,那么我们才会去使用设计模式,就是要使用恰当。还有一个,就是设计模式类似于一个哲学,或者说类似武侠小说里的一个武功秘籍,一定要具备一定的工程代码量的才能够精通。但是,学习设计模式还是有必要的,我们要提前知道设计模式。

1.2、设计模式是怎么来的?

设计模式是通过慢慢迭代出来的,即它是通过满足我们设计原则之后,慢慢迭代出来的。在这里提到两个重要的关键字:

  • 第一个关键字是设计原则。学习设计模式的时候首先要掌握设计原则。
  • 第二个关键字是迭代。因为重复出现,所以慢慢迭代出一些固定的解决固定问题的套路。

1.3、设计模式解决了什么问题?

使用设计模式有一个非常重要的前提条件,就是具体的需求要既有稳定点又有变化点。只有在这种场景下(既有稳定点又有变化点的这种场景下),才可以使用设计模式;这个前提必须要理解好。

  • 稳定点可以理解为就是不会变的东西。
  • 变化点就是经常需要进行变化的,因为具体的一个软件产品,在开发当中,它是长期在运行的,长期需要维护进行开发的,它可能是未来产生的,也有可能是现在产生的;设计模式就是去应对这些变化而产生的。

先想象一下两个极端。如果全是稳定点,也就是软件代码呢它没有什么变化,这种场景下是没有必要使用设计模式的。另外一种极端呢,就是全是变化的,一直都是发生改变的,而且改变是没有固定的方向,它也没有必要使用设计模式。这种极端通常在游戏开放中比较常见,游戏开发当中呢,通常用脚本语言去解决这种全是变化点的问题,因为不需要重新编译、不需要重新启动,脚本可以在上面写很多的复杂的功能,只要重新热更新一下就行了,游戏 的逻辑、还有数据就重新加载到运行的服务器当中了。

好了,那么设计模式具体解决问题的场景是什么呢?就是希望修改少量的代码就可以适应需求的变化。使用设计模式的时候,都是希望修改少量的代码就可以适应需求的变化,如果不满足设计原则,可能总是需要进行重构(推倒重来),即代码写完了以后要推倒重来,重新写好,这个是不符合软件开发的一个需求的;软件开发希望每次是在原来的基础上修改少量的代码就可以应对未来需求的变化,设计模式就是解决这一类问题的。

举一个例子:一间整洁的房间,这个房间里有一个好动的猫,怎么保证房间的整洁呢?这个和使用设计模式要解决问题的时候的场景是一模一样的,整洁的房间代表着一个稳定的点,我们希望这个房间一直是整洁的。那么好动的猫是一个变化点,如果这个猫到处在房间走动的话,那么就会让我们整洁的房间变得不整洁?现在软件开发所要解决个问题就是怎么保证房间的整洁,怎么去解决这个问题呢?把这个猫关在一个笼子里,这样一来猫它会在有限范围内进行活动了,整洁的房间也可以保证了。整洁的房间是我们的目标,好动的猫是时时刻刻都可能发生改变的一些需求;使用设计模式让这一个变化点在有限范围内变化。
在这里插入图片描述

二、设计模式的基础

设计模式跟语言也是相关的,都是利用语言的特性去实现设计模式。对于C++而言,设计模式的基础有哪些呢?第一个需要有一个面向对象的思想,第二个基础是设计原则。

2.1、面向对象思想

面对对象的三个特征:

  • 封装。封装的目的是为了隐藏实现细节,实现模块化;写代码的时候模块化他们互相之间不干扰,不影响(隐藏实现细节,好实现模块化)。
  • 继承。C++的继承跟其他语言还不太一样,其他语言支持单继承,只有C++支持多继承。C++可以继承多个接口或者是多个类。继承主要的目的是希望无需修改原有类的基础上通过继承来实现对功能的扩展。
  • 多态。这个是设计模式最重要的一个特性,很多的设计模式都需要依赖多态的实现。C++的多态有两种,第一个是静态的多态,还有一种是动态的多态。
    • 静态的多态要是指函数的重载;就是同一个函数名,通过参数的不同来可以同时表现出不同的特形态。
    • 动态的多态是指继承的过程当中虚函数重写。很多的设计模式主要都需要依赖这一个特性。

类模型:
在这里插入图片描述

上图描述的是一个多态行为,classBase 是一个基类,基类当中有两个方法,func1func2,都是声明为虚函数;还有一个class Subject类,继承于这个Base类,也有两个方法:func2func3,需要注意func2在基类当中已经存在了,func3它是一个独有方法,有它的一些相对应的其他属性;从它的具体的内存布局来看,在Base类当中有虚函数,就会生成虚函数表指针。

虚函数表指针在编译期就自动生成了,当定义函数中有一个virtual这样的关键字,那么编译器自然而然就会为它去生成一个虚函数表。因此,在编译的时候就会把这个虚函数表的地址赋给相对应的对象,就是每一个Base类的对象都会有一个虚函数表指针。那么虚函数表它是一个什么东西呢?虚函数表就是一个一维数组,这个一维数组当中都记录了这些虚函数的地址;通过偏移就可以调到相对应的方法。

对于Base类而言,有func1func2,子类class Subject同样也会有,因为有virtual关键字,并且基类也有virtual关键字,所以编译器会为类生成一个虚函数表。当构造这个类的时候,同时会把这个虚函数表的指针赋给相对应的对象,并且会在这个类的最前面的位置,也就是子类也会有一个虚函数表指针,这个虚函数表指针它会指向一个一维数组,这个一维数组会记入了相对应的函数地址,如果没有去重写基类的方法的话,比如class Subject类没有重写Base类的func1,那么父类和子类的func1是相同的,因为没有重写。当出现重写时,比如class Subject类重写了Base类的func2,会发生一个替换,会替换为子类自己的;子类自己的函数就会放在虚函数表的最后,比如这里的func3是子类独有的,就会放在第三个位置。

怎么来体现多态的行为呢?这样:

Base *obj = new Subject();

需要注意,如果子类只是普通的继承,也就是Subject就是普通的继承Base,没有这种虚函数重写的话,它会实现一个早绑定(就是会把这个Subject这个类型转换为Base类型),如果没有这种虚函数不写,那么这条语句它是属于早绑定。如果是虚函数重写了,会为它生成这种虚函数表指针,上面的语句它就属于晚绑定(实际指向的是Subject的对象),这是语言的一种机制。晚绑定的这个obj指向的是Subject的对象;早绑定的话这个obj是指向的Base的对象。

晚绑定中调这个func2,实际调用的是Subject对象的func2,因为去找的这个虚函数表指针,然后找到这个虚函数表找到了相对应的方法,根据这个偏移就找到了它。这个就是晚绑定的一个原理,大量的设计模式都是需要依赖这个动态晚绑定的特性。

类的关系:
在这里插入图片描述

2.2、设计原则

前面说了设计模式,怎么现在又出来了一个设计原则呢?设计原则是设计模式还没有产生之前,它已经出来了,设计原则是我们以往一些程序在开发的过程当中总结了一些开发的原则,这些原则都是针对着封装继承多态,接下来跟大家介绍一下常见的九个设计原则有哪些。在项目当中,要知道一块代码,它到底符合什么样的设计原则。

(1)依赖倒置

  • 高层模块不应该依赖低层模块,两者都应该依赖抽象;
  • 抽象不应该依赖具体实现,具体实现应该依赖于抽象。

用一句话来进行总结,就是实现要依赖接口,接口也可以把它转换成一个抽象。也就是说具体实现的代码需要去依赖这一个抽象,具体去使用的这一个接口的用户也需要依赖这一个抽象。这个接口就是通常比较核心的程序员,他会抽象很多很多的接口,一些普通的码农就去把这些接口去实现它就行了。那么对于用户而言,拿着这个接口去实现功能的时候,它也是要依赖这个抽象。也就是说我们主要解决依赖,导致主要解决了一个实现与我们客户使用的一个解耦,中间用一个抽象层,用接口来抽象这一段行为。

这里的定义就是设计模式的作者总结出来的,比较抽象,但是,如果有一定的代码量,肯定一下子能看明白。没有一定代码量的人呢,这里把它抽象并举了个例子:高层跟底层。

以自动驾驶为例子。自动驾驶系统公司是高层,汽车生产厂商为低层,它们不应该互相依赖,一方变动另一方也会跟着变动;而应该抽象一个自动驾驶行业标准,高层和低层都依赖它;这样以来就解耦了两方的变动;自动驾驶系统、汽车生产厂商都是具体实现,它们应该都依赖自动驾驶行业标准(抽象)。
在这里插入图片描述
通俗点说:
这里举了个自动驾驶的这样一个例子,有很多的车企,现在自动驾驶的技术(人工智能这种技术)越来越成熟,当大家想要去争抢这一块领域,都想在自己的车上面去实现这种自动驾驶的系统。假设,有一个自动驾驶系统这样的一个公司,又有很多的厂商,厂商跟这些自动驾驶的公司进行约定,要实现相对应的跟厂商汽车相关的这些自动驾驶的系统,最笨的办法就是这个自动驾驶系统根据每一个公司都去开发相对应的自动驾驶系统。

那么真正的在市场能够运行下来的一种方式是首先会有一个自动驾驶的标准,接下来,这些车企(可以把它想象成我们的底层实现)都需要依赖这一个标准(也就是我们具体的一个接口),就相当于一个用户要调这个接口去实现上层的一些逻辑,自动驾驶也按照这个标准去实现它的这个自动驾。

总结起来:依赖倒置就是说上次高层模块不应该依能依赖低层模块。换一句大家都能听懂的话就是接口的使用者不要依赖具体的实现,而应该要依赖具体的接口;具体的底层的实现,不要依赖用户的使用方式或者是使用习惯,也要依赖这个具体的接口,这样子上面的变化跟下面的变化就解偶了。

(2)开闭原则。一个类应该对扩展(组合和继承)开放,对修改关闭。开辟原则主要针对的是封装和多态。对扩展开放,开放什么东西呢?主要是指变化点,对要抽象出的东西要具体的去扩展它,对变化点的修改要关闭它。在这里会列一些设计原则,先快速的了解,要掌握则需要通过具体代码来理解设计原则,这样在具体写代码的时候,知道代表着一个什么含义,会比较的清晰这个概念。

(3)面向接口

  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口;
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;
  • 减少系统中各部分的依赖关系,从而实现 “高内聚、松耦合” 的类型设计方案。

设计模式主要是面向接口编程,具体的实现要依赖接口,具体使用接口也不要依赖具体的实现。需要注意,设计原则不是一个人总结的,设计原则是有很多人很多人去总结的,所以肯定有重复的、有重叠的部分;但是,他们要有自己的侧重点,自己特别强调的一部分。

(4)封装变化点。将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离。通常是指两个类的依赖越少越好,把这些变化点尽量的不要去修改。跟开辟原则也有一点类似。看具体代码的时候,就知道他们分别指向什么,以及是一个什么场景。

(5)单一职责原则。一个类应该仅有一个引起它变化的原因。职责是一个抽象的概念,是一种变化方向,就是说一个封装的类,它的职责不要太多了,如果类的职责太多,它的变化点就很多。这个和封装变化点有点像,有很多重叠的部分,主要关注它主要针对的是什么就行了。单一职责原则主要是针对封装和多态。

(6)里氏替换。子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责。主要是说的多态,就是类的虚函数重写,如下图片中显示的有具体的重写代码func2函数,子类的这个接口要实现他的职责。

在这里插入图片描述
(7)接口隔离。

  • 不应该强迫客户依赖于它们不用的方法;
  • 一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责;
  • 客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。

(8)组合优于继承。继承耦合度高,组合耦合度低。尽量的使用组合的方式,不要使用继承的方式,它主要是指封装和动态。

(9)最小知道原则。主要是针对封装,让用户不要去选择他不需要的接口,保证最小知道原则,就是对类的了解越少越好,只要知道几个简单的接口就行了,这就是封装巧妙的地方了。

三、如何学习设计模式

接下来探讨一下如何来学习设计模式。

3.1、明确目的

什么是明确目的呢?看这篇文章的朋友分为两类,第一类是刚刚才开始的新手,可能没有接触过具体的工程代码的书写;第二类是已经在公司当中开发多年了。那么就需要明确一个学习设计模式的一个目的。

  • 第一个目是对于基础者的,也就是刚刚参与开发的朋友,要知道在现有的(一个公司,他已经有设计模式了)在使用的具体代码的基础上,扩展代码。就是现在在公司里去开发,那么公司的项目已经非常成熟了,很多的逻辑都已经用设计原则,设计模式已经封装好了,此时需要解决的问题是知道这个设计模式怎么在它的上面扩展代码。
  • 第二个就是做功能抽象,这是开发多年的人群了,现在要做功能抽象,那么如何选择设计模式

3.2、学习步骤

探讨学习的步骤,也是了解设计模式的一个步骤。

(1)设计模式解决了什么问题。注意,跟前面说的设计模式解决了什么问题是不一样的,这里讲的设计模式是具体的某一个设计模式。写一个设计模式,该设计模式解决了什么问题。那么解决什么问题呢?一定要知道它的稳定点是什么,选择这个设计模式来解决问题的稳定点是什么,以及它的变化点是什么,要分析出来,这个是第一步。

(2)该设计模式的代码结构是什么样子?也就是说未来在开发的过程当中看到一段代码,通过观察这个代码结构,快速的能够判定他是什么设计模式。这也是学习的一个目的,一定要非常非常清楚。学到的某一个设计模式,它的代码结构是什么好,这个代码结构包括C、C++语言,它来实现这个设计模式,通常采用什么样的一个结构来实现好,它的代码结构是什么,一定要清楚。

(3)符合哪些设计原则。这个一定要清楚,因为在平常开发的过程当中,一开始的时候,根本不知道这个业务未来是怎么变化,那怎么办呢?首先要先写符合设计原则的代码,当写代码符合设计原则的时候,未来想要把这个代码修改成为某一个设计模式只需要改少量,就可以把设符合设计原则的代码,把它转化成设计模式。符合哪些设计原则,这个就是为什么要学习符合哪些设计原则。

(4)如何扩展代码。就是在具体现有的代码上面,怎么去扩展代码。注意,通常这种扩展代码都是应对的一个变化点,大家注意它是一个变化点,一定要把这个变化点分析出来,具体设计模式,它到底解决了一个什么样的变化点,以及它的稳定点是什么。变化点通常是扩展的方式来进行修改,只有这个样子,才能够写少量改少量的代码,以应对未来需求的变化,这个必须要掌握好。

(5)该设计模式有哪些典型应用场景。学习设计模式的时候,一定要知道它有哪些典型应用,这个主要用来解决做知识迁移,学了设计模式,未来在工作当中怎么去使用它。为什么学习某一个具体知识的时候,一定要把它的典型场景应用,把它给整理一下呢?因为自己学习的时候,学的都是比较抽象的,通常第一步去理解他,理解只是说明你理解他了,知道他的一个逻辑关系了,从理解到能够自如的去使用它,就是做知识迁移,还有一个步骤的,即需要多思考、多实践才能够来实现知识迁移,多重复,重复、重复、不断的去重复,重复的理解。再加上去总结一些典型的应用场景,就可以做知识迁移。

设计模式有哪些典型应用,怎么学习呢?

  • 可以联系目前自己的工作场景,然后去分析是不是适合某一个设计模式。工作场景中恰好要使用到某一个设计模式,然后去总结一下场景,为什么要使用这个设计模式,为未来的时候做知识迁移的时候好提供帮助。
  • 或者在某一个开源框架当中去总结,他使用这个设计模式解决了什么问题,然后他是具体是怎么变化使用的。

总结

思维导图:
在这里插入图片描述
设计模式是软件开发中常用的解决问题的模板,它是通过对软件开发中经常遇到的问题进行总结和抽象产生的。设计模式的基础是面向对象思想和设计原则,通过对这些基础知识的理解,可以更好地学习和应用设计模式。为了有效地学习设计模式,首先需要明确学习的目的,然后按照一定的学习步骤系统学习,才能够真正掌握设计模式的精髓。通过本文的介绍,读者将更加深入地认识设计模式以及学习设计模式的方法。

书籍推荐:

  • 《设计模式-可复用面向对象软件的基础》
  • 《重构与模式》

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/140298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux服务器从零开始训练 RT-DETR 改进项目 (Ultralytics) 教程,改进RTDETR算法(包括使用训练、验证、推理教程)

手把手从零开始训练 RT-DETR 改进项目 (Ultralytics版本) 教程,改进RTDETR算法 本文以Linux服务器为例:从零开始使用Linux训练 RT-DETR 算法项目 《芒果剑指 RT-DETR 目标检测算法 改进》 适用于芒果专栏改进RT-DETR算法 文章目录 百度 RT-DETR 算法介绍改进网络代码汇总第…

CAD Exchanger SDK 有什么新内容?

CAD 交换器 3.23.0,2023 年 11 月强调:- 添加了新版本格式的导入:Autodesk Inventor 2023 和 2024、NX 2306。- 文档经过重大修改,使其更易于导航。它也是现在包含有关 SDK、Web Toolkit 和 Manufacturing Toolkit 的全面信息&…

SQL 存储过程优化

问题:一个复杂的6个表的left jion 语句,发现设置为定时任务后最高时长为18分钟 1、原因分析:对复杂SQL 进行拆分验证 发现是合同明细表和 产品表的left jion 时间过长,发现 合同明细表每天为3w条,之前做过优化 对每个…

(1)(1.14) LightWare SF10/SF11激光雷达

文章目录 前言 1 串行连接 2 I2C 连接 3 参数说明 前言 Lightware SF20 和 LW20 是体积小、测距远(100m)、精度高的测距仪。有两种型号,LW20/Ser 使用串行接口,LW20/I2C 使用 I2C 接口。 1 串行连接 对于串行连接&#xff0…

软件开发项目文档系列之十六如何撰写系统运维方案

前言 项目运维方案是为了确保项目的稳定运行和可持续发展而制定的指导性文档。本文将详细介绍项目运维方案的各个方面,包括硬件和软件基础设施、监控和警报、备份和恢复、安全性、团队组织和沟通等方面。本博客将提供示例和最佳实践,以帮助您更好地理解…

一些分享| 在线笔记、GIF图片生成方法

文章目录 在线笔记视频转GIF 本片博客旨在挖掘一些好用且免费的在线平台,持续更新中~ 正所谓科技解放双手,使用在线平台可以方便快捷地学习办公,节省时间。 在线笔记 语雀 https://www.yuque.com/dashboard 语雀是笔者用得最长最久的平台了…

Leetcode—102.二叉树的层序遍历【中等】

2023每日刷题(二十四) Leetcode—102.二叉树的层序遍历 C语言BFS实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ /*** Return an array of arr…

Springboot项目部署及多环境开发

一、项目部署 我们之前写的代码都是部署在本地的tomcat上,别人是无法访问我们写的程序的。在实际开发中,我们都要将开发完毕的项目部署到公司的服务器上。 我们的代码需要经过编译打包生成一个jar包,这个过程需要借助一个插件来实现。 创建sp…

【微软技术栈】C#.NET 如何使用本地化的异常消息创建用户定义的异常

本文内容 创建自定义异常创建本地化异常消息 在本文中,你将了解如何通过使用附属程序集的本地化异常消息创建从 Exception 基类继承的用户定义异常。 一、创建自定义异常 .NET 包含许多你可以使用的不同异常。 但是,在某些情况下,如果它们…

STL简介+浅浅了解string——“C++”

各位CSDN的uu们好呀,终于到小雅兰的STL的学习了,下面,让我们进入CSTL的世界吧!!! 1. 什么是STL 2. STL的版本 3. STL的六大组件 4. STL的重要性 5. 如何学习STL 6.STL的缺陷 7.为什么要学习string类 …

pinpoint监控tomcat应用,页面显示No data collected

pinpoint安装部署教程大家都可以搜到。这里就不说了。单说一下 页面没有数据的情况。 部署环境,pinpoint安装部署在A服务器上。现在是在C、D、E、F……linux机器上安装pinpoint-agnet 1. 将文件 pinpoint-agent-1.8.5.tar.gz 上传到 服务器C、D、E、F…… 2. 解压…

第十八章DOM操作控制

DOM操作分类: jQuery中的DOM操作 一。设置和获取样式值 1.追加样式 addClass:追加CSS效果 removeClass:去除CSS内容 2.切换样式 3.判断是否含有指定样式:判断的是布尔类型的值 二。内容操作: 1.HTML代码操作 2.TEXT代…

【算法与设计模式】

一、数据结构与算法 1、算法性能评估 时间复杂度、空间复杂度 2、数据结构 数组与列表 队列 堆栈 链表 二叉树 多叉树 递归算法 二、设计模式 1、单例 (1)GIL:线程互斥锁。保证同一时刻只有一个线程在进行。 (2&#xff09…

Git GUI、SSH协议和IDEA中的Git使用详解

目录 前言 一、Git GUI的使用 1. 什么是Git GUI 2. 常见的Git GUI工具 3.使用 4.使用Git GUI工具的优缺点 优点: 缺点: 二、SSH协议 1.什么是SSH协议 2.SSH的主要特点和作用 3.SSH密钥认证的原理和流程 4. SSH协议的使用 三、IEDA使用git …

js随机生成颜色

封装一个函数 返回一个随机颜色 不传参数或者传true返回十六进制, 传false返回rgb模式 script>function Random(n, m) {if (n > m) {let temp nn mm temp}return Math.floor(Math.random() * (m - n 1)) n}function getRandomColor(flag true) {if (fl…

Linux常用命令——bzip2recover命令

在线Linux命令查询工具 bzip2recover 恢复被破坏的.bz2压缩包中的文件 补充说明 bzip2recover命令可用于恢复被破坏的“.bz2”压缩包中的文件。 bzip2是以区块的方式来压缩文件,每个区块视为独立的单位。因此,当某一区块损坏时,便可利用b…

桌面图标设置-将“我的电脑”、“控制面板”添加到桌面

桌面图标设置 1、将“我的电脑”、“控制面板”添加到桌面 桌面鼠标右键-个性化-主题-桌面图标设置-勾选”计算机“、”回收站“、”控制面板“-应用-确定-桌面鼠标右键-排序-名称

数据结构 队列(C语言实现)

目录 1.队列的概念及结构2.队列的代码实现 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站。 1.队列的概念及结构 队列:只允许在…

力扣第516题 最长回文子序列 c++ 动态规划 附Java代码 注释版

题目 516. 最长回文子序列 中等 相关标签 字符串 动态规划 给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。…

3DMAX如何渲染室内效果图?

这可能不是最好的教程,但对于3dmax初学者来说,它具有一定的学习价值和启示意义。 任何在建筑或室内设计领域工作并需要室内或外部空间“艺术家渲染”的人都会熟悉行业巨头Autodesk发布的3ds Max。 3ds Max是此类工作的默认标准,不是因为它在其他3D程序中无法完成,而是因为它…