知识归纳2

1、常见的排序算法,稳定和不稳定:

1. 冒泡排序(Bubble sort)

        冒泡排序是一种简单直观的排序算法,它重复地走访要排序的数列,依次比较两个相邻的元素,如果它们的顺序错误就交换它们。这样每次只将一个最大(最小)值冒泡到数列的最后一位,直到全部排序完成。

        时间复杂度为:O(n^2)。

2. 选择排序(Selection sort)

        选择排序是一种简单直观的排序算法。它的工作原理是每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余未排序的元素中寻找最小(或最大)的元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

        时间复杂度为:O(n^2)。

3. 插入排序(Insertion sort)

        插入排序是一种相对直观的排序算法。它的思想是将一个待排序的元素插入到已经有序的序列中,最终形成一个排好序的序列。初始时,默认第一个元素为已排好序的序列,然后从第二个元素开始,将该元素插入到已排好序的序列中的合适位置,直到全部排序完成。

时间复杂度为:O(n^2)。

4. 希尔排序(Shell sort)

        希尔排序是比插入排序更为高效的排序算法,通过将数组的元素分组,使得每组的元素都比较少,从而减小比较和交换的次数。先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。

        时间复杂度为:O(nlogn)。

5. 归并排序(Merge sort)

        归并排序是一种比较高效的排序算法,采用分治法的思想,将序列递归地分成左右两个部分,对左右两个子序列分别进行排序,最终将排序好的子序列合并成一个有序序列。它的基本思想是将两个或两个以上有序表合并成一个新的有序表,即把待排序序列分为若干个序列,每个序列都是有序的,然后再将有序的子序列合并为整体有序序列。

        时间复杂度为:O(nlogn)。

6. 快速排序(Quick sort)

        快速排序是一种常用的排序算法,采用分治法的思想,通过一趟排序将待排序序列划分成独立的两部分,其中一部分的元素均比另一部分元素小,再分别对这两部分继续进行快速排序,最终得到一个有序序列。在具体实现时,通常选取数组中间的数作为基准数进行排序。

        时间复杂度为:O(nlogn)。

7. 堆排序(Heap sort)

        堆排序是一种利用堆的性质进行排序的算法。将待排序的序列构造成一个大顶堆或小顶堆,依次将堆顶元素和未排序部分的最后一个元素交换,再将剩下的元素重新构造成堆,继续重复以上步骤,直到所有元素排序完成。

        时间复杂度为:O(nlogn)。

8. 计数排序(Counting sort)

        计数排序是一种基于比较的排序算法,适用于序列元素范围比较小的情况。它的思想是针对待排序序列中的每一个元素,在序列中记录小于等于该元素的元素个数,最终实现将元素放入到有序位置的功能。

        时间复杂度为:O(n+k),其中k为整数序列的范围。

9. 桶排序(Bucket sort)

        桶排序是一种基于比较的排序算法,适用于元素范围较小的情况。它将输入数据分配到桶中,并针对每个桶分别进行排序,最后将所有桶合并成一个有序序列。

        时间复杂度为:O(n),但是需要较大的空间来存储桶和桶内元素。

10. 基数排序(Radix sort)

        基数排序是一种非比较排序算法,通过将数据按各个位上的数字进行比较,实现排序的目的。具体实现是从最低位开始,按照位数顺序依次排序,直至按照最高位排序完成。在相同位数上,可以采用荷兰国旗问题的思想分别对每个数位进行桶排序。

        时间复杂度为:O(d*(n+r)),其中d为元素位数,n为元素个数,r为基数。

        稳定排序算法表示如果排序前两个数的值相等,并且他们的下标位置也相等,那么经过排序后,他们仍然保持着排序前的次序不变。换言之,如果对于相等元素的前后顺序要求敏感的数据进行排序,稳定排序算法是不会改变它们的顺序的。例如,在使用稳定排序算法对一组学生成绩进行从小到大排序时,如果某些学生的成绩相同,那么他们的排名次序应当按照他们输入成绩的先后顺序来决定。

        而不稳定排序算法则不保留相等元素的原本次序。对于对相同元素顺序不敏感的数据,使用不稳定排序并不影响排序结果。

        常见的稳定排序算法有冒泡排序、插入排序、归并排序等。

        常见的不稳定排序算法有快速排序、选择排序、堆排序等。

2、编译型语言和解释型语言:

        编译型语言和解释型语言是两种不同的编程语言类型,其中编译型语言指的是需要在特定计算机上预先编译成可执行目标代码的语言,而解释型语言指的是在执行代码时即时解释成机器代码的语言。

        具体来说,编译型语言的代码需要经过一系列预处理、编译、链接等步骤生成可执行二进制代码,然后将其传输到目标计算机上运行。编译型语言需要在不同平台上进行重新编译,并且生成的可执行代码执行速度很快,因为它们直接运行在计算机硬件上,无需中间解释。

        而解释型语言的代码直接被解释器读取,并且在运行时动态解释成机器码,而不是生成可执行文件。解释型语言代码的执行速度比编译型语言慢,但更加灵活,在运行时可变,因为解释器可以根据用户的输入信息即时调整代码执行方式。

        编译型语言的代表有 C语言、C++、Go等,而解释型语言的代表有Python、Perl、JavaScript等。不过,实际上并不是所有的编程语言都能严格被归类为编译型语言或解释型语言,也有一些语言存在“混合型”的特性。

3、死锁和避免死锁:

        死锁是指在多线程或多进程并发访问共享资源时,彼此相互等待对方释放锁的现象。如果不加限制和控制,死锁可能导致程序卡死,影响程序的执行效率。所以,我们需要了解死锁产生的原因,以及如何避免死锁。

        死锁产生的原因:

  1. 互斥条件:指在资源使用时不能被共享。
  2. 请求和保持条件:指进程在请求资源的同时保持已有的资源。
  3. 不剥夺条件:指资源在没有被进程释放前,不能被其他进程强制抢占。
  4. 循环等待条件:指多个进程之间形成一种环形等待资源的状态。

        避免死锁的方法:

  1. 避免使用多个锁:尽量避免使用多个锁,如果无法避免,可以使用统一的加锁顺序。
  2. 加锁时不阻塞:每次尝试获取锁时,如果锁已被占用,线程不应该阻塞等待,而是应该立即释放已经获取的锁,等待一段时间后再尝试获取。
  3. 定时释放锁:在使用锁的时候,设置一个超时时间,如果超时时间到了锁还没有被释放,就强制释放锁。
  4. 避免循环依赖:在多个线程之间的操作中,通过协调加锁的顺序,避免多个线程之间出现循环依赖,从而避免死锁。

4、进程3态及其转化:

进程在操作系统内部具有三种状态:就绪(Ready)、执行(Running)和阻塞(Blocked)状态。

  1. 就绪状态:进程准备好了,等待分配CPU时间片来执行,但还没有得到CPU的时间片。
  2. 执行状态:CPU正在执行进程。
  3. 阻塞状态:进程因为某些原因(如等待IO操作完成等)无法执行,将等待内核的某个事件、结果或信号等。此时,该进程不会占用CPU资源。

这三种状态之间的互相转换如下:

  1. 就绪状态 -> 执行状态:当调度程序选择了该进程,并分配了CPU时间片后,该进程状态由就绪状态变为执行状态。
  2. 执行状态 -> 就绪状态:当进程的时间片用完或者某些事件发生时,该进程状态由执行状态变成就绪状态。
  3. 执行状态 -> 阻塞状态:当进程在执行过程中需要等待某个事件的完成时,该进程状态由执行状态变为阻塞状态。
  4. 阻塞状态 -> 就绪状态:当进程在阻塞状态时等待的事件完成后,该进程状态由阻塞状态变为就绪状态。
  5. 就绪状态 -> 阻塞状态:当进程因为某些条件无法立即执行时,该进程状态由就绪状态变为阻塞状态。
  6. 阻塞状态 -> 执行状态:当等待进程在一个事件后重新进入就绪状态,并且已经被调度程序选中时,该进程状态由阻塞状态变为执行状态。

        有一些情况下进程状态是不能转变的。例如,在进程处于运行状态时,如果系统内存资源不足,那么它就不能切换到就绪状态,因为没有足够的内存分配给它,此时系统可能会强制杀死该进程。同样地,如果一个进程被挂起,比如等待某个资源,但是该资源却永远无法被释放(例如因为死锁),这个进程就永远无法从挂起状态转换到运行状态。这些情况可能会导致进程的一些状态无法转化,需要通过其他手段解决。

5、linux初始化过程:

Linux的初始化过程涉及到内核引导、启动系统服务等多个步骤。以下是Linux初始化过程的简要描述:

  1. BIOS引导:计算机开机后,首先会执行BIOS程序。BIOS进行硬件初始化,加载引导程序。
  2. 引导程序加载内核:引导程序从硬盘、软盘或网络中加载内核到内存中。
  3. 内核初始化:内核读取并解压缩后,进行初始化操作,包括建立CPU、内存、硬件设备的关系等。此时,内核进程被创建并运行。
  4. 运行init进程:内核在初始化之后会执行init进程。init是Linux中的第一个用户级进程,其任务是启动系统服务,并为用户分配一个交互式shell终端。
  5. 系统服务启动:init进程会启动各种系统服务,如网络、时间同步、日志、软件包管理等,使其在系统初始化时就可用。
  6. 用户登录:系统服务启动之后,用户可以通过登录界面或虚拟控制台登录,然后访问操作系统和本地应用程序。

在Linux初始化过程中,还会涉及到加载设备驱动、配置网络、挂载文件系统等操作。这些步骤的顺序和细节可能会因不同Linux发行版而有所不同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值