算法期末ppt复习(新手,个人见解)

算法分析与设计

复习大纲

总纲

总复习

第一章 绪论

主要内容

算法的概念

• 算法问题求解基础

• 算法的描述

• 算法的设计技术

• 1、算法的重要特性

• (1)确定性

• 算法的每一种运算必须要有确切的定义,即每

一种运算应该执行何种动作必须相当清楚、无二义性。

• (2)能行性

• 算法中有待实现的运算都是相当基本的,每种

运算在原理上能在有限时间内完成。

• (3)输入

• 这些算法有0个或多个输入,这些输入是在算

法开始之前给出的量,它取自特定的对象集合。

• (4)输出

• 没有输出的算法是无效的算法,因此算法要有

一个或多个输出,这些输出是同输入有某种特定关系的

量。

• (5)有穷性

• 一个算法总是在执行了有穷步运算后终止。

• 阐明几个要点:

• 算法的每一步骤都必须清晰、明确。

• 算法所处理的输入的值域必须仔细定义。

• 同样一种算法可以用几种不同的形式来描述。• 可能存在集中解决相同问题的算法。

• 针对同一问题的算法可能会基于完全不同的解

题思路,而且解题速度也会有显著不同。

• 2、 算法问题求解基础

算法作为我们的研究对象,要讨论算法的各个方面,需要从以下几个方面入手。

• 1.理解问题

• 2.了解计算机设备的性能

• 3.在精确解法和近似解法间做选择

• 4.确定适当的数据结构

• 5.算法设计技术

• 6.详细表述算法的方法

• 7.证明算法的正确性

• 8.分析算法

• 9.为算法写代码

设计了一个算法,除了检查其正确性外,更重要的

是看该算法的效率了,算法有两种效率:时间效率及空间效率。

时间效率指的是该算法的执行需要多长时间;

空间效率指的是该算法的执行需要多少额外的存储空间。

此外,分析算法还要看它是否简单,或具有一般性。

• 所谓简单性:算法容易让人理解与实现,那它的效率

是否也很高吗?大多数情况下是否定的,但依然有些

简单的算法效率要高于复杂的算法,因此,我们在大

多数情况要在简单性与高效性之间进行权衡筛选。

• 所谓一般性:包含两层含义,一是解决问题所采用一

般性的算法,二是算法所接受输入的一般性。对于第

一方面,给出解决问题一般性的算法,可能更好解决。

如判断两个数是否互质的问题,即它们两个是否只拥

有惟一的公约数1。我们可以这样设计算法:先求这

两个数的公约数,再判断此数是否为1。我们也可以

设计其它的算法,但做起来可能是困难的或上完全不

可能的。对于第二个方面,输入的范围要一般,即在

测试算法时,不能仅凭借手头上仅有的几个数据进行

测试,要关心边界数据以及海量数据,这可能是用户

经常使用的输入数据。

一、蛮力法

人们是这样描述它的:蛮力法是一种简单

直接地解决问题的方法,常常直接基于问

题的描述和所涉及的概念定义。这里的

“ 力” 是指计算机的能“ 力” ,而不是人的智“ 力” 。我们也可以用“ 直接做吧!”

来描述蛮力法的策略。

冒泡排序:

冒泡排序
#include <iostream>
#include <algorithm>
using namespace std;
int main()   
{
    int arr[] = {34,24,67,435,97,46,34,742,34,23,89,657};
    int n = sizeof(arr)/sizeof(arr[0]);
     for (int i = 0; i < n-1; i++) {
        // 外层循环控制比较次数
        for (int j = 0; j < n-i-1; j++) {
            // 遍历数组从0到n-i-1
            // 交换如果找到元素大于下一个元素
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
return 0;
}

选择排序;

#include <iostream>
#include <algorithm>
using namespace std;
int main()   
{
    int arr[] = {34,24,67,435,97,742,34,23,89,657};
    int n = sizeof(arr)/sizeof(arr[0]);
    // 外层循环控制比较次数
   for (int i = 0; i < n - 1; i++) {
        int min_idx = i;  // 假设当前位置为最小值索引
        // 内层循环找到真正的最小值索引
        for (int j = i + 1; j < n; j++) {
            // 如果找到更小的元素,更新最小值索引
            if (arr[j] < arr[min_idx]) {
                min_idx = j;/// 更新最小值索引
            }
        }
        // 手动交换找到的最小元素与i位置的元素
        // 使用临时变量
        if (min_idx != i) {
            // 交换
            int temp = arr[i];// 保存i位置的元素
            arr[i] = arr[min_idx];// 将i位置的元素赋给min_idx
            arr[min_idx] = temp;// 将i位置的元素赋给min_idx
        }
    }
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
   }
   return 0;
}

顺序查找

#include <iostream>
#include <algorithm>
using namespace std;
int main()   
{
    int arr[] = {34,24,67,435,97,46,34,742,34,23,89,657};
    int n = sizeof(arr)/sizeof(arr[0]);
    int key = 67;//要查找的元素
    for (int i = 0; i < n; i++) {// 外层循环控制比较次数
        // 遍历数组
        if (arr[i] == key) {
            // 如果找到元素,输出位置并返回
            cout << "找到元素" << key << "的位置为" << i << endl;
            return 0;
        }
    }
    cout << "未找到元素" << key << endl;
    return 0;
}

简单的字符串匹配算法。

#include <iostream>
#include <string.h>
using namespace std;
int string_match(char* text, const char* pattern) {
    int textLen = strlen(text);
    int patternLen = strlen(pattern);
    // 遍历文本串的每一个可能的起始位置
    for (int i = 0; i <= textLen - patternLen; i++) {
        int j;
        // 比较从当前起始位置开始的子串与模式串
        for (j = 0; j < patternLen; j++) {
            // 如果发现不匹配的字符,跳出循环
            if (text[i + j] != pattern[j])
                break;
        }
        // 如果j等于模式串的长度,说明找到了匹配
        if (j == patternLen)
            return i; // 返回匹配起始位置
    }
    // 未找到匹配,返回-1或其他表示未找到的值
    return -1;
}
int main() {
    char text[] = "Hello, this is a simple example.";
    char pattern[] = "simple";
    int index = string_match(text, pattern);// 调用匹配函数
    if (index != -1) {
        cout << "字符串下标:" << index << endl;// 输出匹配位置
    } else {
        cout << "文本未找到字符串." << endl;// 输出未找到匹配
    }
    return 0;
}

二、分治法

无论人们在祈祷什么,他们总是在祈祷一

个奇迹。每一个祈祷都可以简化为:伟大

的上帝呀,请让两个二相加不等于四吧。

——伊万·屠格涅夫(18181883),俄国作家和短篇小说家

分治法可能是最著名的通用算法设计技术了。虽然它的名气可能和它那好记的名字有

关,但它的确是当之无愧的:很多非常有效

的算法实际上是这个通用算法的特殊实现。其实,分治法是按照以下方案工作的:

  1. 将问题的实例划分为同一个问题的几个较小 的实例,最好拥有同样的规模。
  2. 对这些较小的实例求解(一般使用递归方法, 但在问题规模足够小的时候,有时也会使用

一些其他方法)。

  1. 如果必要的话,合并这些较小问题的解,以 得到原始问题的解。

  1. 合并排序是一种分治排序算法。它把一个输入数组一分 为二,并对它们递归排序,然后把这两个排好序的子数组合并为原数组的一个有序排列。在任何情况下,这个

算法的时间效率都是Θ(nlogn),而且它的键值比较次数非

常接近理论上的最小值。它的主要缺点是需要相当大的

额外存储空间。

  1. 快速排序是一种分治排序算法,它根据元素值和某些事 先确定的元素的比较结果,来对输入元素进行分区。快速排序十分有名,这不仅因为对于随机排列的数组,它

是一种较为出众的nlogn效率算法,而且因为它的最差效

率是平方级的。

  1. 折半查找是一种对有序数组进行查找O(logn)效率算法。 它是应用分治技术的一个非典型案例,因为在每次迭代

中,它只需要解决两个问题的一个。

  1. 大整数乘法是一种处理两个n位整数相乘的分治算法。
  2. 分治技术可以成功地应用于两个重要的计算几何问题: 最近对问题和凸包问题。

三、减治法

减治技术利用了一种关系:一个问题给 定实例的解和同样问题较小实例的解之间

的关系。一旦建立了这样一种关系,我们

既可以从顶至下(递归地),也可以从底

至上(非递归地)地来运用。减治法有3

主要的变种:

减去一个常量;

减去一个常数因子;

减去的规模是可变的。

在减常量变种中,每次算法迭代总是从实例规模 中减去一个规模相同的常量。一般来说,这个常量

等于一,但减二的情况偶尔也会发生,例如,有的算法会根据实例规模为奇数和偶数的不同情况,分别做不同的处理。这一类思维主要在排序问题中应用到。

减常因子技术意味着在算法的每次迭代中,总是 才实例的规模中减去一个相同的常数因子。在大多

数应用中,这样的常数因子等于二。

最后,在减治法的减可变规模变种中,算法在每 次迭代时,规模减小的模式都是不同的。计算最大

公约数的欧几里德算法是这种情况的一个很好的例

子。

这类问题是在组合问题中出现。

分治法和减治法区别

分治法是对分解的子问题分别求解,需要对子问题的解进行合并,而减治法只对一个子问题求解,并且不需要进行解的合并。应用减治法(例如减

半法)得到的算法通常具有如下递推式:

T(n) =

 

0

îíì T(n/ 2) +1

 

n =1 n >1

位串法生成幂集

n=3,元素为{a1,a2,a3}

方法: 每一个子集与一个3位二进制串b1b2b3对应,ai

于该子集时,bi=1,否则 bi=0

二进制串:

000, 001, 010, 011, 100, 101, 110, 111

对应子集:

, {a3}, {a2}, {a2,a3}, {a1}, {a1,a3}, {a1,a2}, {a1,a2,a3}

约瑟夫斯问题(Josephus)

在约瑟夫斯环中最后的幸存者是谁?

偶数情况:J(2k)=2J(k)-1

奇数情况:J(2k+1)=2J(k)+1

二进制表示:J(6)=J(1102)=1012=5J(7)=J(1112)=1112=7

20

下列( )不是衡量算法的标准。

c

• A时间效率 B空间效率 C问题的难度 D

适应能力

下列程序段S执行次数为( )。

c

• for (i=1;i<=n;i++)

• for (j=0;j<=n;j++)

• S;

• A n2 B n2/2 C n(n+1) D n(n+1)/2

二维最近邻点问题,如果使用分治法,对于一个子集上的某一点,另一个子集上需

D

要检查的点的个数是( )。

• A 1B 2C 6D 8

C

例题一

给出{23 13 49 6 31 19 28}采用快速排序思想

进行排序时划分的过程示意图。

左右为原数组的元素位置。

例题二

n枚硬币,其中有一枚硬币是假币,且假

币的重量较轻,通过一架天平找出假币。

比较次数最少。

  1. 开始
  2. 输入:硬币总数 n
  3. 判断 n 是否为1
    • 是:输出 硬币编号0为假币(或直接指出唯一一枚硬币为假币),结束
  4. 初始化:将硬币分为两组,尽量均等(若不能均分,一组会比另一组多一枚)
  5. 天平称重:将两组硬币分别放在天平的两端
  6. 根据天平状态分支:
    • 如果天平平衡:假币在未参与本次称重的那一枚中,直接进入第9步
    • 如果天平不平衡:假币在较轻的那一组中
  7. 更新范围:根据天平结果,缩小假币可能存在的范围至较轻的那一组
  8. 递归执行:从第4步开始,对新范围内的硬币重复上述过程
  9. 确定并输出假币位置:经过递归缩小范围后,最终确定并输出假币的确切位置
  10. 结束

例题三

【问题描述】

蛇形矩阵是由1开始的自然数依次排列成

的一个矩阵上三角形。

【要求】

【数据输入】本题有多组数据,每组数据

由一个正整数N组成。(N不大于100

【数据输出】对于每一组数据,输出一个

N行的蛇形矩阵。两组输出之间不要额外的空

行。矩阵三角中同一行的数字用一个空格分

开。行尾不要多余的空格。

【样例输入】

5

【样例输出】

1 3 6 10 15

2 5 9 14

4 8 13

7 12

11

#include<iostream>
using namespace std;
int main()
{
    int N,i,j,x,y;
    cin>>N;//输入行数
    x=1;
    for(i=1;i<=N;i++) {//外循环:循环N次,共N行
        x=x+i-1;
        cout<<x<<" ";//输出每行首个数字
        y=x;
        for(j=i;j<N;j++) {//内循环:循环输出每行余下数字
            y=j+y+1;
            cout<<y<<" ";
        }
        cout<<endl;
    }
    return 0;
}

例题 四

在没有电话的时代,摩尔斯电码是无线电传输领

域中的一种常用代码。电码以短信号(短点,o)和

长信号(长点,-)的不同组合表示各种文字。例如

o—表示英文字母J,而表示英文字母M

假设有一本以n个长点和mnm<=100)个短点

组成的、包含所有信号的字典。例如:n=m=2,就会

包含如下信号。

–oo

-o-o

-oo-

o–o

o-o-

oo–

这些信号已按照字典顺序排列好了。-

ASKII码是45,而oASCII码是111。因此,

按照字典顺序,-在前,o在后。给定nm

时,编写代码计算出此字典的第k

k<=1,000,000,000,000)个信号。例如:上

述字典的第四个信号是o–o

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值