跳过正文
  1. 文章列表/

DAY 10 算法

·2791 字·6 分钟· ·
技术 Cs-10 C/C++ 编程 计算机专业 算法
作者
qlAD
做技术的黑客心态加上开放共进的态度是成长和越过高山幽谷的秘籍!
目录
计算机基础 - 这篇文章属于一个选集。
§ : 本文

你没看错,这么快就要学习算法了,虽然我们的 C 语言基础还不够扎实,但是我们可以先从 一些基本概念和算法入门的前置知识 开始。

在实际讨论时,我们通常会将 “数据结构与算法” 简称为 “算法”。

第一次听说算法?
#

在高中阶段,我们就已经学习过算法框图,但是那个时候我们还没有接触到计算机,所以并没有真正理解算法的概念。

算法的定义
#

算法(Algorithm)是指用来解决特定问题的一系列指令,它是指令的有序集合,是指一系列操作,一步一步地解决一个问题。

在计算机程序中,算法常常与数据结构联系在一起,算法是指用来解决特定问题的指令集合,而数据结构则是指用来存储和组织数据的集合。

image.png

简单理解就是:算法是对数据进行 增删改查 的方法。数据结构是程序的骨架,而算法则是程序的灵魂。

数据结构
#

还没开始学呢,就冒出来了一个看起来很高级的新词:数据结构。

数据结构 是计算机存储、组织数据的方式,它是指数据 元素 的集合、关系和规则,以及这些数据元素之间的相互关系。

举个简单的例子:

整型 int 型数据,它可以存储整数,一堆整型数据组成的集合叫作 数组,数组就是一种数据结构。

int scores[10] = {85, 90, 78, 88, 95, 82, 79, 91, 76, 84};

显而易见数组有更多的优势:

  • 数据量大时,可以快速访问任意元素;
  • 数组可以动态调整大小,方便添加或删除元素;
  • ……

办法总比困难多
#

解决一个问题,肯定不止一种办法,写程序也是一样。

算法优劣对比
#

不同的算法在不同的场景下,有着不同的优势。那么如何衡量一个算法的优劣呢?

—— 用时少、花费小

举个例子:

从上海到北京,有多种交通工具可以选择。假设你要选择最快捷的交通工具,你会怎么做?

  • 第一种方法:坐飞机。
  • 第二种方法:坐高铁。
  • 第三种方法:坐长途汽车。

结合用时少,花费小的原则对以上方法进行对比:

方法用时花费优势劣势
坐飞机2-3小时700-2000元用时最少费用最高
坐高铁4.5-6小时550-1200元用时较短,费用适中相对飞机稍慢
坐长途汽车12-15小时300-500元费用最低用时最长
  • 坐飞机:最快,但价格较高且流程较为复杂。
  • 坐高铁或火车:时间适中,价格也较合理,适合大多数人。
  • 坐长途汽车:费用最少,但需要忍受较长的旅途时间。

没有最好的算法,只有最合适的算法。

对于一个 有钱并且赶时间 的人来说,飞机可能最适合他。
对于一个喜欢沿途风景的 旅行者 来说,高铁或火车可能更合适。
对于一个 贫穷 的人来说,坐长途汽车可能是最经济的选择。

在程序中也是一样,每个人的电脑配置不同,需求也不同,所以算法的选择也可能有所不同。

算法与程序
#

虽然算法多种多样,但程序都有着共同的目标:解决问题。算法的目标是解决问题,所以算法的设计者往往会考虑众多因素:

在计算机程序中一个算法应该考虑的往往是:

  1. 正确性:正确性是指算法能够满足具体问题的需求,程序运行正常,无语法错误,能够通过典型的软件测试,达到预期的需求。
  2. 可读性:可读性指的是算法遵循标识符命名规则,简洁易懂,注释语句恰当,方便自己和他人阅读,便于后期修改和调试。
  3. 健壮性:健壮性指的是算法对非法数据以及操作有较好的反应和处理。

当然除了以上三个目标,好的算法还会考虑到其他因素:

就是上边提到的 用时少、花费小,算法的设计者也会考虑到算法的效率。

在计算机中所代表的就是所需运行时间更少(时间复杂度更低)、占用内存空间更小(空间复杂度更低)。

生活中的算法
#

其实在接触计算机和编程之前,我们就已经在生活中使用算法了。比如:

查字典(二分查找法)
#

Peek 2024-09-16 22-13.gif
图片来源 Hello 算法

数据结构 的角度,我们可以把字典视为一个已排序的 “数组”;从 算法 的角度,我们可以将上述查字典的一系列操作看作 “二分查找”。

斗地主(插入排序法)
#

image.png
图片来源 Hello 算法

上述整理扑克牌的方法本质上是 “插入排序” 算法,它在处理小型数据集时非常高效。许多编程语言的排序库函数中都有插入排序的身影。

比如:C++ 标准库中的 std::list::sort()

#include <iostream>
#include <list> // For std::list

int main() {
    // Create a list of integers
    std::list<int> myList = {12, 11, 13, 5, 6};

    // Sort the list using the list's sort() method
    myList.sort();

    std::cout << "Sorted list: ";
    for (int num : myList) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

那数据结构呢 ?
#

在生活中也可以看到数据结构的影子。比如:

你有一个书架,书架上放着很多书籍,你按照某种顺序(例如按字母顺序或按大小)排列这些书籍。

书架与数据结构的对应关系:

  • 书架上的每本书 就像数据结构中的 元素
  • 书架的排列顺序 类似于数据结构中元素的 顺序,比如数组或链表。
  • 添加新书 相当于在数据结构中插入新元素。
  • 取一本书 就像在数据结构中访问特定的元素。
  • 移走一本书 就是删除数据结构中的一个元素。
  • ……

在书架的例子中:

  • 如果你按照书籍的大小从小到大排列,那就像是一个 排序数组
  • 如果你将书架设计成可以灵活插入和移除书籍,那么它就像一个 链表,每本书可以随意插入和移除,位置也可以动态调整。

设计算法
#

设计算法简单来说就是设计一个工作流。

自己设计排序
#

假设你有一副扑克牌,点面全是数字,你想把这副牌按照数字大小排序,你会怎么做?

对于一个小数组:[3, 1, 4, 1],我们要用刚才提到的插入排序法进行排序。

  1. 开始排序:从第二个元素 1 开始排序。

  2. 保存当前元素:将 1 保存到 key 变量中。

  3. 寻找插入位置:

    向前检查第一个元素 3,因为 3 > 1,所以需要把 3 移到右边。

  4. 移动元素:

    将 3 移到右边,变成 [3, 3, 4, 1]。

  5. 插入当前元素:

    把 key(1)放到前面,变成 [1, 3, 4, 1]。

  6. 继续处理下一个元素:

对下一个 4 执行相同操作,最后数组变成 [1, 3, 4, 1],继续处理最后一个 1。

最终,整个数组变成 [1, 1, 3, 4],这是经过插入排序后的结果。

用 C 语言来实现上述步骤:

#include <stdio.h>

// 插入排序函数
void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        // 移动元素,将大于 key 的元素移到右边
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

// 打印数组
void printArray(int arr[], int size) {
    int i;
    for (i = 0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

int main() {
    int arr[] = {3, 1, 4, 1};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("Original array: \n");
    printArray(arr, n);

    insertionSort(arr, n);

    printf("Sorted array: \n");
    printArray(arr, n);

    return 0;
}

写完之后,相见恨晚。
#

有的编程语言已经提供了现成的排序算法,比如 Python。

arr = [3, 1, 4, 1]
arr.sort()
print(arr)

为什么要学习算法?
#

如上文提到的 Python 的 sort() 方法、 C++ 标准库中的 std::list::sort() 就是例子。既然有了现成的算法,为什么还要自己设计一个呢?

  1. 自己会在学习和设计过程中感觉到快乐愉悦
  2. 自己设计的算法可以更好地满足需求
  3. 自己设计的算法可以深入理解算法的原理
  4. 为了比赛拿奖,为了刷题,为了面试,为了面试官的面试技巧。

作为一名程序员,通常情况下会优先使用封装好的库函数来解决问题,尤其是在库函数能够高效、可靠地满足需求时。这是因为库函数通常经过优化和广泛测试,可以提高开发效率并减少错误。

学习 & 练习算法
#

算法:搜索、查找、排序、双指针、回溯、分治、动态规划、贪心、位运算、数学。
数据结构:数组、栈、队列、字符串、链表、树、图、堆、哈希表。

LeetCode
#

LeetCode 是一个算法学习网站,提供了大量的算法题目,可以用来训练自己的算法能力。

算法竞赛
#

算法竞赛是程序员的必修课,也是衡量一个程序员水平的重要标准。

ACM 竞赛
蓝桥杯:蓝桥杯是一个算法竞赛,由蓝桥杯官方举办,主要面向高校学生。

计算机基础 - 这篇文章属于一个选集。
§ : 本文

相关文章

DAY 9 C 语言进阶语法
技术 Cs-09 C/C++ 编程 计算机专业
这篇文章主要是 C 语言进阶语法的内容,主要包括指针、数组、结构体、枚举、宏、函数指针、文件操作、字符串处理等。
DAY 8 C 语言入门语法
·5947 字·12 分钟
技术 Cs-08 C/C++ 编程 计算机专业
本篇文章主要是补充基础语法中未提到的部分,包括控制流程、函数、运算符、数组等内容。
DAY 7 C 语言基础语法
·7591 字·16 分钟
技术 Cs-07 C/C++ 编程 计算机专业
这篇文章介绍了 C 语言的基本语法,包括变量声明、控制结构和函数定义等内容,适合初学者学习和参考。

Giscus 点击加载评论