78、计算机中的数制与排序算法详解

计算机中的数制与排序算法详解

1. 数制系统概述

在计算机编程里,我们常常会和各种数制系统打交道,常见的有十进制、二进制、八进制和十六进制。下面为你详细介绍这些数制系统的特点:
- 十进制(Base 10) :这是我们日常生活中最常用的数制,其数字范围是 0 到 9。最低位数字是 0,最高位数字是 9,也就是比基数 10 小 1。
- 二进制(Base 2) :计算机内部采用的数制,仅有 0 和 1 两个数字。最低位数字是 0,最高位数字是 1,比基数 2 小 1。
- 八进制(Base 8) :数字范围从 0 到 7,常用于简化二进制数的表示。
- 十六进制(Base 16) :由于需要 16 个数字,除了 0 到 9 之外,还使用字母 A 到 F 来表示十进制的 10 到 15。最低位数字是 0,最高位数字相当于十进制的 15,比基数 16 小 1。

各数制系统的关键信息总结如下表:
| 数制系统 | 基数 | 数字范围 | 最低位数字 | 最高位数字 |
| ---- | ---- | ---- | ---- | ---- |
| 十进制 | 10 | 0 - 9 | 0 | 9 |
| 二进制 | 2 | 0, 1 | 0 | 1 |
| 八进制 | 8 | 0 - 7 | 0 | 7 |
| 十六进制 | 16 | 0 - 9, A - F | 0 | F(十进制 15) |

各数制系统中,每个数位的位置都有不同的位权值。例如,十进制数从右往左的位权值依次是 1、10、100、1000 等。下面是各数制系统中最右边四个位置的位权值表:
| 数制系统 | 位权值(从右往左) |
| ---- | ---- |
| 十进制 | 1, 10, 100, 1000 |
| 十六进制 | 1, 16, 256, 4096 |
| 二进制 | 1, 2, 4, 8 |
| 八进制 | 1, 8, 64, 512 |

2. 数制转换方法

不同数制之间的转换是编程中的常见操作,下面为你介绍一些常用的转换方法:
- 八进制转二进制 :把每个八进制数字替换成对应的三位二进制数。例如,八进制数 7 转换为二进制就是 111。
- 十六进制转二进制 :将每个十六进制数字替换成对应的四位二进制数。比如,十六进制数 F 转换为二进制是 1111。
- 其他数制转十进制 :把每个数字的十进制等效值乘以其位权值,然后将结果相加。例如,二进制数 1101 转换为十进制的计算过程为:(1\times2^3 + 1\times2^2 + 0\times2^1 + 1\times2^0 = 8 + 4 + 0 + 1 = 13)。

以下是一些具体的数制转换示例:
- 二进制 110101011000 转八进制和十六进制
- 转八进制:从右往左每三位一组,不足三位的在左边补 0,得到 011 010 101 100,对应的八进制数是 6530。
- 转十六进制:从右往左每四位一组,不足四位的在左边补 0,得到 1101 0101 1000,对应的十六进制数是 D58。
- 十六进制 FACE 转二进制 :F 对应 1111,A 对应 1010,C 对应 1100,E 对应 1110,所以结果是 1111 1010 1100 1110。
- 八进制 7316 转二进制 :7 对应 111,3 对应 011,1 对应 001,6 对应 110,结果是 111 011 001 110。

3. 负数的二进制表示:补码

计算机采用补码(Two’s Complement Notation)来表示负数。下面为你详细介绍补码的形成过程:
- 求反码(One’s Complement) :使用 C 语言中的按位取反运算符 ~ 对二进制数的每一位进行取反操作,即 0 变为 1,1 变为 0。
- 求补码 :在反码的基础上加 1。

以十进制数 13 为例,其 32 位二进制表示是 00000000 00000000 00000000 00001101 ,具体计算过程如下:

value:
00000000 00000000 00000000 00001101
~value (i.e., value’s ones complement):
11111111 11111111 11111111 11110010
Two’s complement of value:
11111111 11111111 11111111 11110011

补码表示负数的原理是,一个数和它的补码相加结果为 0。例如:

 00000000 00000000 00000000 00001101
+11111111 11111111 11111111 11110011
------------------------------------
 00000000 00000000 00000000 00000000

在减法运算中,计算机实际上是通过加上减数的补码来实现的,例如 x = a - value 可以转换为 x = a + (~value + 1)

4. 排序算法简介

排序是将数据按照一定的顺序(通常是升序或降序)排列的操作。常见的排序算法有选择排序、插入排序和归并排序。下面为你简单介绍这些算法:
- 选择排序(Selection Sort) :简单但效率较低的排序算法。每次迭代选择剩余元素中的最小元素,然后与当前位置的元素交换。
- 插入排序(Insertion Sort) :将未排序的数据插入到已排序序列的合适位置。
- 归并排序(Merge Sort) :效率较高但实现较复杂的递归排序算法,采用分治法将数组分成两部分,分别排序后再合并。

下面是选择排序的 mermaid 流程图:

graph TD;
    A[开始] --> B[初始化数组];
    B --> C[外层循环,遍历数组长度 - 1 次];
    C --> D[初始化最小元素索引为当前索引];
    D --> E[内层循环,遍历剩余元素];
    E --> F{当前元素是否小于最小元素};
    F -- 是 --> G[更新最小元素索引];
    F -- 否 --> E;
    G --> H[交换最小元素和当前元素];
    H --> I{外层循环是否结束};
    I -- 否 --> C;
    I -- 是 --> J[结束];
5. 算法效率:大 O 表示法

大 O 表示法(Big O Notation)用于估算算法的最坏情况运行时间,也就是算法解决问题所需的最大工作量。下面为你介绍几种常见的大 O 表示法:
- O(1) :常数时间复杂度,算法的运行时间与数据规模无关。例如,判断数组的第一个元素是否等于第二个元素,无论数组有多少个元素,都只需要一次比较。
- O(n) :线性时间复杂度,算法的运行时间与数据规模成正比。例如,判断数组的第一个元素是否等于其他任何元素,最多需要 n - 1 次比较。
- O(n²) :二次时间复杂度,算法的运行时间与数据规模的平方成正比。例如,判断数组中是否有重复元素,需要进行大约 (n^2/2 - n/2) 次比较。当数据规模较小时,O(n²) 算法的性能影响不明显,但随着数据规模的增大,性能会显著下降。

6. 选择排序算法实现

以下是使用 C 语言实现的选择排序算法代码:

// Fig. D.1: figD_01.c
// The selection sort algorithm. 
#define SIZE 10
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// function prototypes 
void selectionSort(int array[], size_t length);
void swap(int array[], size_t first, size_t second);
void printPass(int array[], size_t length, unsigned int pass, size_t index);

int main(void)
{
    int array[SIZE]; // declare the array of ints to be sorted 

    srand(time(NULL)); // seed the rand function 

    for (size_t i = 0; i < SIZE; i++) {
        array[i] = rand() % 90 + 10; // give each element a value 
    }

    puts("Unsorted array:");

    for (size_t i = 0; i < SIZE; i++) { // print the array 
        printf("%d  ", array[i]);
    }

    puts("\n");
    selectionSort(array, SIZE);
    puts("Sorted array:");

    for (size_t i = 0; i < SIZE; i++) { // print the array 
        printf("%d  ", array[i]);
    }
} 

// function that selection sorts the array 
void selectionSort(int array[], size_t length)
{
    // loop over length - 1 elements 
    for (size_t i = 0; i < length - 1; i++) {
        size_t smallest = i; // first index of remaining array 

        // loop to find index of smallest element 
        for (size_t j = i + 1; j < length; j++) {
            if (array[j] < array[smallest]) {
                smallest = j;
            }
        }

        swap(array, i, smallest); // swap smallest element 
        printPass(array, length, i + 1, smallest); // output pass 
    } 
}

// function that swaps two elements in the array 
void swap(int array[], size_t first, size_t second)
{
    int temp = array[first];
    array[first] = array[second];
    array[second] = temp;
} 

// function that prints a pass of the algorithm 
void printPass(int array[], size_t length, unsigned int pass, size_t index)
{
    printf("After pass %2d: ", pass);

    // output elements till selected item 
    for (size_t i = 0; i < index; i++) {
        printf("%d  ", array[i]);
    }

    printf("%d* ", array[index]); // indicate swap 

    // finish outputting array 
    for (size_t i = index + 1; i < length; i++) {
        printf("%d  ", array[i]);
    }

    printf("%s", "\n               "); // for alignment 

    // indicate amount of array that is sorted 
    for (unsigned int i = 0; i < pass; i++) {
        printf("%s", "--  ");
    }

    puts(""); // add newline 
} 

选择排序算法的效率是 O(n²),因为它包含两层嵌套的 for 循环。外层循环遍历数组长度 - 1 次,内层循环遍历剩余元素,每次迭代都需要比较和交换操作。

综上所述,掌握不同数制系统的表示和转换方法,以及常见排序算法的原理和实现,对于计算机编程至关重要。通过合理选择算法,可以提高程序的性能和效率。希望本文能帮助你更好地理解这些概念。

计算机中的数制与排序算法详解

7. 插入排序算法

插入排序是一种简单直观的排序算法,它的工作原理是将未排序数据插入到已排序序列的合适位置。以下是插入排序的详细步骤:
1. 从数组的第二个元素开始,将其视为未排序部分的第一个元素。
2. 取出该元素,在已排序序列中从后向前扫描。
3. 如果已排序序列中的元素大于取出的元素,则将该元素向后移动一位。
4. 重复步骤 3,直到找到一个小于或等于取出元素的位置。
5. 将取出的元素插入到该位置。
6. 重复步骤 1 - 5,直到整个数组排序完成。

插入排序的代码示例如下:

#include <stdio.h>

#define SIZE 10

void insertionSort(int array[], int length) {
    for (int i = 1; i < length; i++) {
        int key = array[i];
        int j = i - 1;

        while (j >= 0 && array[j] > key) {
            array[j + 1] = array[j];
            j = j - 1;
        }
        array[j + 1] = key;
    }
}

int main() {
    int array[SIZE] = {72, 34, 88, 14, 32, 12, 34, 77, 56, 83};

    printf("Unsorted array:\n");
    for (int i = 0; i < SIZE; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    insertionSort(array, SIZE);

    printf("Sorted array:\n");
    for (int i = 0; i < SIZE; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

插入排序的效率也是 O(n²),因为在最坏情况下,每次插入操作都需要移动已排序序列中的所有元素。

8. 归并排序算法

归并排序是一种高效的排序算法,采用分治法的思想。它的基本步骤如下:
1. 分解 :将数组分成两个子数组,分别对这两个子数组进行排序。
2. 合并 :将两个已排序的子数组合并成一个有序的数组。

下面是归并排序的代码示例:

#include <stdio.h>

#define SIZE 10

void merge(int array[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;

    int L[n1], R[n2];

    for (int i = 0; i < n1; i++)
        L[i] = array[left + i];
    for (int j = 0; j < n2; j++)
        R[j] = array[mid + 1 + j];

    int i = 0;
    int j = 0;
    int k = left;

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            array[k] = L[i];
            i++;
        } else {
            array[k] = R[j];
            j++;
        }
        k++;
    }

    while (i < n1) {
        array[k] = L[i];
        i++;
        k++;
    }

    while (j < n2) {
        array[k] = R[j];
        j++;
        k++;
    }
}

void mergeSort(int array[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;

        mergeSort(array, left, mid);
        mergeSort(array, mid + 1, right);

        merge(array, left, mid, right);
    }
}

int main() {
    int array[SIZE] = {72, 34, 88, 14, 32, 12, 34, 77, 56, 83};

    printf("Unsorted array:\n");
    for (int i = 0; i < SIZE; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    mergeSort(array, 0, SIZE - 1);

    printf("Sorted array:\n");
    for (int i = 0; i < SIZE; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    return 0;
}

归并排序的效率是 O(n log n),因为每次分解操作将数组分成两部分,递归深度为 log n,而每次合并操作的时间复杂度是 O(n)。

9. 不同排序算法的比较

不同的排序算法在时间复杂度、空间复杂度和稳定性等方面存在差异。以下是选择排序、插入排序和归并排序的比较表格:
| 排序算法 | 时间复杂度 | 空间复杂度 | 稳定性 |
| ---- | ---- | ---- | ---- |
| 选择排序 | O(n²) | O(1) | 不稳定 |
| 插入排序 | O(n²) | O(1) | 稳定 |
| 归并排序 | O(n log n) | O(n) | 稳定 |

从表格中可以看出,归并排序的时间复杂度最低,在处理大规模数据时性能更好,但它需要额外的空间来合并子数组。选择排序和插入排序的实现简单,但时间复杂度较高,适用于小规模数据。

10. 排序算法的应用场景

不同的排序算法适用于不同的应用场景,以下是一些常见的应用场景和对应的推荐算法:
- 小规模数据 :选择排序和插入排序实现简单,对于小规模数据可以快速完成排序。
- 大规模数据 :归并排序的时间复杂度较低,适合处理大规模数据。
- 对空间要求高 :选择排序和插入排序的空间复杂度为 O(1),只需要常数级的额外空间。
- 需要稳定排序 :插入排序和归并排序是稳定的排序算法,适合对稳定性有要求的场景。

11. 总结

本文详细介绍了计算机中不同数制系统的表示和转换方法,以及常见排序算法的原理和实现。数制系统包括十进制、二进制、八进制和十六进制,掌握它们之间的转换方法对于理解计算机内部数据表示至关重要。排序算法方面,选择排序简单但效率低,插入排序适用于小规模数据,而归并排序在大规模数据处理中表现出色。同时,大 O 表示法可以帮助我们评估算法的效率,从而选择合适的算法来提高程序的性能。

在实际应用中,我们应根据数据规模、空间要求和稳定性等因素选择合适的排序算法。希望通过本文的介绍,你能对这些概念有更深入的理解,并在编程中灵活运用。

以下是归并排序的 mermaid 流程图:

graph TD;
    A[开始] --> B[分解数组];
    B --> C{数组长度是否为 1};
    C -- 是 --> D[返回数组];
    C -- 否 --> E[分成左右子数组];
    E --> F[递归排序左子数组];
    E --> G[递归排序右子数组];
    F --> H[合并左右子数组];
    G --> H;
    H --> I[结束];

通过合理选择算法和数据表示方式,我们可以优化程序的性能,提高开发效率。希望大家在实际编程中能够灵活运用这些知识,解决遇到的问题。

基于matlab建模FOC观测器采用龙贝格观测器+PLL进行无传感器控制(Simulink仿真实现)内容概要:本文档主要介绍基于Matlab/Simulink平台实现的多种科研仿真项目,涵盖电机控制、无人机路径规划、电力系统优化、信号处理、图像处理、故障诊断等多个领域。重点内容之一是“基于Matlab建模FOC观测器,采用龙贝格观测器+PLL进行无传感器控制”的Simulink仿真实现,该方法通过状态观测器估算电机转子位置速度,结合锁相环(PLL)实现精确控制,适用于永磁同步电机等无位置传感器驱动场景。文档还列举了大量相关科研案例算法实现,如卡尔曼滤波、粒子群优化、深度学习、多智能体协同等,展示了Matlab在工程仿真算法验证中的广泛应用。; 适合人群:具备一定Matlab编程基础,从事自动化、电气工程、控制科学、机器人、电力电子等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①学习并掌握FOC矢量控制中无传感器控制的核心原理实现方法;②理解龙贝格观测器PLL在状态估计中的作用仿真建模技巧;③借鉴文中丰富的Matlab/Simulink案例,开展科研复现、算法优化或课程设计;④应用于电机驱动系统、无人机控制、智能电网等实际工程仿真项目。; 阅读建议:建议结合Simulink模型代码进行实践操作,重点关注观测器设计、参数整定仿真验证流程。对于复杂算法部分,可先从基础案例入手,逐步深入原理分析模型改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值