当前位置: 首页 > news >正文

基于C语言的数组从入门到精通

简介:本篇文章主要介绍了一维数组,二维数组,字符数组的定义,数组的应用,数组的核心代码解析,适用于0基础的初学者.

  • C语言数组

  • 1.一维数组
    • 1.1定义
      • 1.1.1声明
        • 语法:数据类型 数组名[数组大小];
        • 示例:int arr[5];
      • 1.1.2初始化
        • a.静态初始化
          • 完全初始化:int arr[5] = {1, 2, 3, 4, 5};
          • 部分初始化:int arr[5] = {1, 2};(剩余元素初始化为0)
          • 特殊初始化:int arr[] = {1, 2, 3, 4, 5};(编译器自动计算大小)
        • b.动态初始化
          • 使用malloc
            • int *arr = (int *)malloc(5 * sizeof(int));
            • for (int i = 0; i < 5; i++) { arr[i] = i + 1; }
          • 使用calloc
            • int *arr = (int *)calloc(5, sizeof(int));
            • for (int i = 0; i < 5; i++) { arr[i] = i + 1; }
    • 1.2一维数组访问
      • 1.2.1通过索引访问
        • 语法:数组名[索引]
        • 示例:int value = arr[0];
      • 1.2.2边界检查
        • if (index >= 0 && index < n) { int value = arr[index]; }
    • 1.3一维数组操作
      • 1.3.1遍历数组
        • 使用for循环;
        • for (int i = 0; i < 数组大小; i++) {    printf("%d ", arr[i]);}
      • 1.3.2数组排序
        • a.选择排序
          • for (int i = 0; i < 数组大小 - 1; i++) {    int minIndex = i;    for (int j = i + 1; j < 数组大小; j++) {        if (arr[j] < arr[minIndex]) {            minIndex = j;        }    }    int temp = arr[minIndex];    arr[minIndex] = arr[i];    arr[i] = temp;}
        • b.冒泡排序
          • for (int i = 0; i < 数组大小 - 1; i++) {    for (int j = 0; j < 数组大小 - i - 1; j++) {        if (arr[j] > arr[j + 1]) {            int temp = arr[j];            arr[j] = arr[j + 1];            arr[j + 1] = temp;        }    }}
      • 1.3.3数组搜索
        • a.线性搜索
          • int search(int arr[], int 数组大小, int key) {    for (int i = 0; i < 数组大小; i++) {        if (arr[i] == key) {            return i;        }    }    return -1;}
        • b.二分搜索
          • int binarySearch(int arr[], int 数组大小, int key) {    int left = 0, right = 数组大小 - 1;    while (left <= right) {        int mid = left + (right - left) / 2;        if (arr[mid] == key) {            return mid;        }        if (arr[mid] < key) {            left = mid + 1;        } else {            right = mid - 1;        }    }    return -1;}
      • 1.3.4数组长度
        • 使用sizeof运算符计算
        • int length = sizeof(numbers) / sizeof(numbers[0]);
    • 1.4数组与指针
      • 1.4.1数组名作为指针:数组名是指向数组第一个元素的常量指针:int *ptr = arr;
      • 1.4.2指针运算:移动到下一个元素:ptr++;
      • 1.4.3指针与数组的关系:*(arr + i)等价于arr[i]
    • 1.5数组作为函数参数
      • 1.5.1传递一维数组:函数声明:void func(int arr[], int 数组大小);函数调用:int arr[5] = {1, 2, 3, 4, 5}; func(arr, 5);
  • 2.二维数组
    • 2.1定义
      • 2.1.1声明
        • 数据类型 数组名[行数][列数];
        • 示例:int arr[3][4];
      • 2.1.2初始化
        • 完全初始化:int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
        • 部分初始化:int arr[3][4] = { {1, 2}, {5, 6}, {9, 10}};(剩余元素初始化为0)
        • 特殊初始化:int arr[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};(编译器自动计算行数)
    • 2.2访问
      • 2.2.1通过索引访问:int value = arr[行索引][列索引];
      • 2.2.2示例:int value = arr[1][2][3];
    • 2.3操作
      • 2.3.1遍历二维数组
        • 使用嵌套for循环:
        • for (int i = 0; i < 行数; i++) {    for (int j = 0; j < 列数; j++) {        printf("%d ", arr[i][j]);    }    printf("\n");}
    • 2.4二维数组与指针
      • 2.4.1数组名作为指针:int (*ptr)[列数] = arr;
      • 2.4.2指针运算:ptr++;(移动到下一行)
      • 2.4.3指针与数组的关系:*(*(arr + i) + j)等价于arr[i][j]
    • 2.5二维数组作为函数参数
      • 2.5.1传递二维数组:函数声明:void func(int arr[][列数], int 行数);函数调用:int arr[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; func(arr, 3);
  • 3.字符数组
    • 3.1定义
      • 3.1.1声明
        • 语法:char 数组名[数组大小];
        • 示例:char str[10];
      • 3.1.2初始化
        • a.字符初始化
          • a.1完全初始化
            • 定义:初始化数组长度所有的值
            • char str[5] = {'H', 'e', 'l', 'l', 'o',}; //长度为5
          • a.2部分初始化
            • 定义:初始化元素的个数,小于数组的长度,没有初始化部分使用'\0'补齐
            • char str[10] = {'H', 'e', 'l', 'l', 'o'}; //剩余元素初始化为'\0')
          • a.3特殊初始化
            • 定义:不定义数组的长度,由初始化元素的个数来决定
            • char str[ ] = {'H', 'e', 'l', 'l', 'o'}; //长度为5
        • b.字符串初始化
          • b.1完全初始化
            • 定义:初始化数组长度所有的值
            • char str[6] = {"hello"};  //长度为6,最后一位是补'\0'
            • char str[6] = "hello";  //长度为6,最后一位是补'\0'
          • b.2部分初始化
            • 定义:初始化元素的个数,小于数组的长度,没有初始化部分使用'\0'补齐
            • char str[4] = {"hi"}; //剩余元素初始化为'\0')
          • b.3特殊初始化
            • 定义:不定义数组的长度,由初始化元素的个数来决定
            • char str[ ] = {"hello"}; //长度为6
    • 3.2访问
      • 3.2.1通过索引访问
        • 字符数组中的每个字符都可以通过其索引进行访问。索引从0开始,最后一个字符的索引是length - 1,其中length是字符串的长度。char str[] = "Hello";printf("First character: %c\n", str[0]);  // 输出 'H'printf("Last character: %c\n", str[4]);   // 输出 'o'
      • 3.2.2使用指针访问
        • 字符数组的名称可以作为指向数组首元素的指针来使用。可以通过指针运算来访问字符数组中的各个字符。char str[] = "Hello";char *ptr = str;printf("First character: %c\n", *ptr);    // 输出 'H'printf("Second character: %c\n", *(ptr + 1));  // 输出 'e'// 使用循环遍历字符数组while (*ptr != '\0') {    printf("%c", *ptr);    ptr++;}printf("\n");
      • 3.3.3边界检查
        • 为了避免越界访问,应该始终进行边界检查,确保索引在合法范围内。char str[] = "Hello";int length = strlen(str);int index = 2;if (index >= 0 && index < length) {    printf("Character at index %d: %c\n", index, str[index]);} else {    printf("Index out of bounds\n");}
      • 3.2.4遍历字符数组
        • 使用for循环或while循环来遍历字符数组,直到遇到字符串结束符\0。char str[] = "Hello";int length = strlen(str);for (int i = 0; i < length; i++) {    printf("%c", str[i]);}printf("\n");
        • 使用while循环char str[] = "Hello";char *ptr = str;while (*ptr != '\0') {    printf("%c", *ptr);    ptr++;}printf("\n");
      • 3.3.5二维字符数组
        • 可以通过多个索引来访问每个字符。char strArray[3][6] = {"Hello", "World", "C"};// 访问第一个字符串的第一个字符printf("out %c\n", strArray[0][0]);// 遍历所有字符串并输出for (int i = 0; i < 3; i++) {    for (int j = 0; j < 6 && strArray[i][j] != '\0'; j++) {        printf("%c", strArray[i][j]);    }    printf("\n");}
      • 3.3.6动态内存分配的数组
        • 对于使用malloc或calloc动态分配的字符数组,同样可以通过索引或指针进行访问,但需要注意内存管理,使用完后要释放内存。#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {    char *str = (char *)malloc(6 * sizeof(char));    strcpy(str, "Hello");    // 通过索引访问    printf("First character: %c\n", str[0]);    // 通过指针访问    char *ptr = str;    while (*ptr != '\0') {        printf("%c", *ptr);        ptr++;    }    printf("\n");    free(str);  // 释放动态分配的内存    return 0;}
    • 3.3字符数组操作
      • 3.3.1字符及字符串输入
        • scanf
          • int scanf(const char *format, ...):从标准输入读取格式化输入。
          • char str[100];scanf("%s", str);  // 读取一个单词(遇到空格、换行或制表符停止)
        • fscanf
          • int fscanf(FILE *stream, const char *format, ...):从指定文件流读取格式化输入。
        • fgets
          • char *fgets(char *str, int n, FILE *stream):从指定文件流读取最多n-1个字符,直到遇到换行符或EOF。自动添加\0作为字符串结束符。
          • char str[100];fgets(str, sizeof(str), stdin);  // 读取一行字符串
        • getline(非标准)
          • ssize_t getline(char **lineptr, size_t *n, FILE *stream):动态分配内存读取一行字符串。适用于不确定长度的输入。
          • char *line = NULL;size_t len = 0;ssize_t read = getline(&line, &len, stdin);if (read != -1) {    printf("Read line: %s", line);    free(line);}
        • gets(不推荐)
          • char *gets(char *str):从标准输入读取一行字符串,直到遇到换行符或EOF。由于不检查缓冲区溢出,存在安全风险,已被弃用。
      • 3.3.2字符及字符串输出
        • printf
          • int printf(const char *format, ...):向标准输出写入格式化输出。
          • char str[] = "Hello, World!";printf("%s\n", str);  // 输出字符串
        • fprintf
          • int fprintf(FILE *stream, const char *format, ...):向指定文件流写入格式化输出。
        • puts
          • int puts(const char *str):将字符串str和一个换行符写入标准输出。
          • char str[] = "Hello, World!";puts(str);  // 输出字符串并换行
        • fputs
          • int fputs(const char *str, FILE *stream):将字符串str写入指定文件流,不添加换行符。
          • char str[] = "Hello, World!";fputs(str, stdout);  // 输出字符串,不换行
        • sprintf
          • int sprintf(char *str, const char *format, ...):将格式化数据写入字符串str。
          • char buffer[50];sprintf(buffer, "Value: %d", 42);  // 格式化输出到字符串printf("%s\n", buffer);
        • snprintf
          • int snprintf(char *str, size_t size, const char *format, ...):将格式化数据写入字符串str,最多写入size-1个字符,确保以\0结尾。
          • snprintf(buffer, sizeof(buffer), "Value: %d", 42);  // 安全的格式化输出printf("%s\n", buffer);
      • 3.3.3字符处理函数<ctype.h> 库
        • 字符检查函数
          • isalnum(c):检查字符c是否为字母或数字。
          • isalpha(c):检查字符c是否为字母(包括大写和小写字母)。
          • iscntrl(c):检查字符c是否为控制字符。
          • isdigit(c):检查字符c是否为数字(0-9)。
          • isgraph(c):检查字符c是否为图形字符(非空字符,不包括空格)。
          • islower(c):检查字符c是否为小写字母。
          • isprint(c):检查字符c是否为可打印字符(包括空格)。
          • ispunct(c):检查字符c是否为标点符号。
          • isspace(c):检查字符c是否为空白字符(如空格、制表符、换行符等)。
          • isupper(c):检查字符c是否为大写字母。
          • isxdigit(c):检查字符c是否为十六进制数字(0-9, a-f, A-F)。
        • 字符转换函数
          • tolower(c):将字符c转换为小写,如果不是大写字母则保持不变。
          • toupper(c):将字符c转换为大写,如果不是小写字母则保持不变。
      • 3.3.4字符串处理函数<string.h> 库
        • a.字符串操作
          • a1.计算字符串长度strlen(s):计算字符串s的长度,不包括结尾的\0。size_t len = strlen("Hello, World!");
          • a2.复制字符串
            • strcpy(dest, src):将字符串src复制到dest,包括结尾的\0。char dest[50];strcpy(dest, "Hello, World!");
            • strncpy(dest, src, n):最多复制src的前n个字符到dest,如果src长度小于n,则用\0填充剩余部分。char dest[50];strncpy(dest, "Hello, World!", 5);dest[5] = '\0'; // 保证字符串以'\0'结尾
          • a3.连接字符串
            • strcat(dest, src):将字符串src连接到dest的末尾,覆盖dest原有的结尾\0。char dest[50] = "Hello, ";strcat(dest, "World!");
            • strncat(dest, src, n):最多将src的前n个字符连接到dest的末尾。char dest[50] = "Hello, ";strncat(dest, "World!", 5);
        • b.字符串比较
          • b1.比较两个字符串
            • strcmp(s1, s2):比较两个字符串s1和s2,返回值为0表示相等,负数表示s1小于s2,正数表示s1大于s2。int result = strcmp("apple", "banana");
            • strncmp(s1, s2, n):最多比较两个字符串的前n个字符。int result = strncmp("apple", "apples", 5);
          • b2.忽略大小写比较
            • strcasecmp(s1, s2):忽略大小写比较两个字符串(非标准,但广泛支持)。int result = strcasecmp("Apple", "apple");
            • strncasecmp(s1, s2, n):忽略大小写最多比较两个字符串的前n个字符(非标准,但广泛支持)。int result = strncasecmp("Apple", "apple", 5);
        • c.字符串查找与替换
          • c1.查找字符
            • strchr(s, c):在字符串s中查找字符c第一次出现的位置,返回指向该位置的指针,未找到则返回NULL。
            • strrchr(s, c):在字符串s中查找字符c最后一次出现的位置,返回指向该位置的指针,未找到则返回NULL。char *ptr = strrchr("Hello, World!", 'o');
          • c2.查找子串strstr(s1, s2):在字符串s1中查找子串s2第一次出现的位置,返回指向该位置的指针,未找到则返回NULL。char *ptr = strstr("Hello, World!", "World");
          • c3.分割字符串char *strtok(char *str, const char *delim):strtok(s, delim):将字符串s按分隔符delim分割成多个子串,每次调用返回一个子串,直到没有更多子串时返回NULL。
        • d.内存操作
          • d1.内存复制void *memcpy(void *dest, const void *src, size_t n):从src复制n个字节到dest。void *memmove(void *dest, const void *src, size_t n):与memcpy类似,但处理重叠内存区域更安全。
          • d2.内存设置void *memset(void *s, int c, size_t n):将n个字节的内容设置为字符c。
        • e.字符串转换.
          • e1.字符串转整数int atoi(const char *s):将字符串s转换为整数。long atol(const char *s):将字符串s转换为长整数。long long atoll(const char *s):将字符串s转换为长整数(64位)。
          • e2.字符串转浮点数double atof(const char *s):将字符串s转换为双精度浮点数。
          • e3.格式化输入输出int sprintf(char *str, const char *format, ...):按照格式化字符串format将数据写入字符串str。int sscanf(const char *str, const char *format, ...):从字符串str中读取数据,并根据格式化字符串format解析到参数中。
    • 3.4字符数组与指针
      • 3.4.1字符数组与指针的定义
        • 字符数组的名称实际上是一个指向数组首元素的常量指针。可以使用数组名来访问数组中的元素,就像使用指针一样。
        • char str[] = "Hello";printf("First character: %c\n", *str);  // 输出 'H'str 是一个指向字符数组首元素的指针。*str 解引用指针,获取第一个字符。
      • 3.4.2指针赋值与字符数组
        • 可以通过指针变量指向字符数组,并使用指针运算来遍历或修改字符数组中的内容。
        • char str[] = "Hello";char *ptr = str;// 使用指针遍历字符数组while (*ptr != '\0') {    printf("%c", *ptr);    ptr++;}printf("\n");
          • ptr 指向字符数组的首元素。
          • *ptr 访问当前指针指向的字符。
          • ptr++ 移动指针到下一个字符。
      • 3.4.3指针算术与字符数组
        • 指针算术允许你通过指针偏移量来访问字符数组中的任意元素。
        • char str[] = "Hello";
        • char *ptr = str;
        • printf("Second character: %c\n", *(ptr + 1));  // 输出 'e'
        • *(ptr + 1) 访问指针指向位置后一个字符。
      • 3.4.4使用动态分配字符数组
        • 使用malloc或calloc动态分配字符数组时,返回的是一个指向字符数组的指针。
        • #include <stdio.h>#include <stdlib.h>#include <string.h>int main() {    char *str = (char *)malloc(6 * sizeof(char));    strcpy(str, "Hello");    // 使用指针访问动态分配的字符数组    printf("First character: %c\n", *str);    // 使用循环遍历字符数组    for (int i = 0; i < 5; i++) {        printf("%c", str[i]);    }    printf("\n");    free(str);  // 释放动态分配的内存    return 0;}
      • 3.4.5字符串字面量与指针
        • 字符串字面量(如 "Hello")实际上是存储在只读内存区域中的字符数组,使用时会返回一个指向该区域的指针。
        • char *str = "Hello";  // str 指向字符串字面量printf("First character: %c\n", *str);  // 输出 'H'// 注意:不能修改字符串字面量的内容// *str = 'h';  // 这将导致未定义行为
      • 3.4.6多维字符数组与指针
        • 对于多维字符数组(如二维字符数组),可以通过多个指针来访问每个字符。
        • char strArray[3][6] = {"Hello", "World", "C"};// 使用指针访问多维字符数组for (int i = 0; i < 3; i++) {    char *ptr = strArray[i];    while (*ptr != '\0') {        printf("%c", *ptr);        ptr++;    }    printf("\n");}
      • 3.4.7 指针与数组的关系总结
        • 数组名是常量指针:数组名等价于指向数组首元素的指针,但不能修改数组名本身。
        • 指针算术:可以使用指针算术(如ptr + n)来访问数组中的任意元素。
        • 解引用指针:使用*ptr可以访问指针所指向的字符。
        • 动态分配:动态分配的字符数组通过指针进行访问和操作,记得释放内存。
        • 字符串字面量:字符串字面量是只读的,不能修改其内容。
    • 3.5字符数组作为函数参数
      • 3.5.1定义
        • 当将字符数组作为参数传递给函数时,实际上是传递了一个指向数组首元素的指针。
      • 3.5.2传递字符数组声明调用
        • 函数声明:void func(char str[]);
        • 函数调用:char str[100] = "Hello"; func(str);
      • 3.5.3函数实现
        • void printString(char *str) {    while (*str != '\0') {        putchar(*str++);    }    putchar('\n');}int main() {    char str[] = "Hello";    printString(str);  // 传递字符数组的指针    return 0;}
  • 4.思维导图
    • 根据思维导图,能够了解所要学习数组所有核心点的知识

5.数组核心代码

        5.1数组声明与定义

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{// 一维数组声明与静态初始化int arr1[5];int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr3[3][4];int arr4[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8},{9, 10, 11, 12}};// 动态数组(使用malloc)int *arr5 = (int *)malloc(5 * sizeof(int));if (arr5 == NULL) 
{// 内存分配失败处理perror("Memory allocation failed");exit(EXIT_FAILURE);}for (int i = 0; i < 5; i++) 
{arr5[i] = i + 1;}// 打印一维数组 arr2printf("一维数组 arr2: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr2[i]);}printf("\n");// 打印二维数组 arr4printf("二维数组 arr4:\n");for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) 
{printf("%d ", arr4[i][j]);}printf("\n");}// 打印动态数组 arr5printf("动态数组 arr5: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr5[i]);}printf("\n");// 释放动态分配的内存free(arr5);return 0;
}

        5.2数组的访问

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main(int argc, const char *argv[])
{// 一维数组声明与静态初始化int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr4[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};// 访问一维数组第一个元素int value1 = arr2[0];printf("Value1 (arr2[0]): %d\n", value1);// 访问二维数组第二行第三列元素int value2 = arr4[1][2];printf("Value2 (arr4[1][2]): %d\n", value2);// 边界检查示例int index = 3;if (index >= 0 && index < 5) 
{int value3 = arr2[index];printf("Value3 (arr2[%d]): %d\n", index, value3);} else {printf("Index out of bounds\n");}// 测试超出范围的索引index = 5;if (index >= 0 && index < 5) {int value3 = arr2[index];printf("Value3 (arr2[%d]): %d\n", index, value3);} else {printf("Index out of bounds\n");}return 0;
}

        5.3数组的遍历

#include <stdio.h>int main(int argc, const char *argv[])
{// 一维数组声明与静态初始化int arr2[5] = {1, 2, 3, 4, 5};// 二维数组声明与静态初始化int arr4[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8},{9, 10, 11, 12}};// 遍历一维数组printf("一维数组 arr2: ");for (int i = 0; i < 5; i++) 
{printf("%d ", arr2[i]);}printf("\n");// 遍历二维数组printf("二维数组 arr4:\n");for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) 
{printf("%d ", arr4[i][j]);}printf("\n");}return 0;
}/*一维数组:
arr2 初始化为 {1, 2, 3, 4, 5}。
使用单层 for 循环遍历并打印每个元素。
二维数组:
arr4 初始化为指定的二维数组。
使用嵌套的 for 循环遍历并打印每个元素,每行结束后打印换行符。
通过这个示例代码,你可以更好地理解C语言数组的遍历方法。
*/

        5.4数组的排序

                5.4.1冒泡排序

 a.冒泡排序的原理:依次比较相邻的元素,如果前面的比后面的大(小)就进行交换每一趟比较后,就会得到一个最大值(小),该值不进行下一轮的比较对剩余的部分,再次进行前面的操作,直到剩余一个元素为止,排序成功。

        天蓝色:待排序

        绿色:正在比较的数组元素

        橙色:已经拍好的数组元素

b.冒泡排序的要素

b1.需要双重循环来解决:

        外层循环:控制遍历的次数。总共需要 n-1 次遍历。
        i 从 0 到 n-2。
        内层循环:比较相邻的元素并交换它们。
        j 从 0 到 n-i-2。

b2.每趟的比较次数 +所在趟数 == 元素总个数.
b3.每次内层循环结束后,最大的元素会被“冒泡”到数组的末尾。
b4.比较和交换:
        如果 arr[j] 大于 arr[j + 1],则交换这两个元素。
        使用临时变量 temp 来交换元素的值。

#include <stdio.h>int main(int argc, const char *argv[]){int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);int i, j, temp;printf("原始数组: \n");for (i = 0; i < n; i++) 
{printf("%d ", arr[i]);}printf("\n");// 冒泡排序算法for (i = 0; i < n - 1; i++) 
{for (j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交换 arr[j] 和 arr[j + 1]temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}printf("冒泡排序后的数组: \n");for (i = 0; i < n; i++) 
{printf("%d ", arr[i]);}printf("\n");return 0;
}

                   5.4.2选择排序

a.选择排序的原理:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

b.选择排序的算法

b1.外层循环 for (int i = 0; i < n - 1; i++) 遍历数组中的每个元素,i 表示当前考虑的元素位置。

b2.内层循环 for (int j = i + 1; j < n; j++) 从当前元素的下一个元素开始遍历,寻找从 i 开始的最小元素。

b3.如果在内层循环中发现比当前最小值更小的元素,则更新最小值的索引 minIndex

b4.内层循环结束后,如果 minIndex 不等于 i,则交换 arr[i] 和 arr[minIndex]

c.选择排序注意:选择排序的时间复杂度为O(n^2),其中n是数组的长度。它不是一种高效的排序算法,但它的实现简单,对于小型数据集来说足够使用。对于大型数据集,通常会使用更高效的排序算法,如快速排序、归并排序或堆排序。

#include <stdio.h>
int main(int argc, const char *argv[])
{int arr[] = {64, 25, 12, 22, 11}; // 待排序数组int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度// 外层循环,遍历数组中的每个元素for (int i = 0; i < n - 1; i++) 
{// 假设当前元素为最小值int minIndex = i;// 内层循环,从当前元素的下一个元素开始遍历,寻找最小值for (int j = i + 1; j < n; j++) 
{// 如果找到更小的元素,则更新最小值的索引if (arr[j] < arr[minIndex]){minIndex = j;}}// 如果最小值不是当前元素,则交换它们if (minIndex != i) 
{int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}// 打印排序后的数组printf("排序后的数组: ");for (int i = 0; i < n; i++) 
{printf("%d ", arr[i]);}printf("\n");return 0;
}

                5.4.3插入排序

         是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。在C语言中,插入排序的实现通常涉及到数组的操作。

a.插入排序的原理

a1.初始状态: 假设数组的第一个元素已经是有序的(因为一个元素本身就是有序的)。

a2.排序过程:

        从数组的第二个元素开始,依次将每个元素插入到前面已经排好序的子数组中。

        对于每个待插入的元素,从后向前比较它与已排序子数组中的元素。

         如果待插入元素小于已排序子数组中的某个元素,则将该元素向后移动一位,为待插入元素腾出位置。

        重复这个过程,直到找到合适的位置插入待插入元素。

a3.重复步骤2: 继续处理数组中的下一个元素,直到整个数组都被排序。

b.插入排序的算法

b1.外层循环 for (int i = 1; i < n; i++) 从数组的第二个元素开始遍历,因为第一个元素默认是已排序的。

b2.int key = arr[i]; 保存当前要插入的元素。

b3.int j = i - 1; 初始化一个指针,指向当前元素的前一个位置。

b4.内层循环 while (j >= 0 && arr[j] > key) 将大于 key 的元素向后移动一位,直到找到 key 应该插入的位置。

b5..arr[j + 1] = key; 将 key 插入到正确的位置。

#include <stdio.h>
int main(int argc, const char *argv[])
{int arr[] = {12, 11, 13, 5, 6}; // 待排序数组int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度// 插入排序算法for (int i = 1; i < n; i++) 
{int key = arr[i]; // 当前要插入的元素int j = i - 1;// 将大于key的元素向后移动一位while (j >= 0 && arr[j] > key) 
{arr[j + 1] = arr[j];j--;}// 插入key到正确的位置arr[j + 1] = key;}// 打印排序后的数组printf("排序后的数组: ");for (int i = 0; i < n; i++) 
{printf("%d ", arr[i]);}printf("\n");return 0;
}

6.数组练习题

相关文章:

基于C语言的数组从入门到精通

简介:本篇文章主要介绍了一维数组,二维数组,字符数组的定义,数组的应用,数组的核心代码解析,适用于0基础的初学者. C语言数组 1.一维数组 1.1定义 1.1.1声明 语法:数据类型 数组名[数组大小];示例:int arr[5]; 1.1.2初始化 a.静态初始化 完全初始化&#xff1a;int arr[5] {1…...

CLOUDFLARE代理请求重定向你太多次

现象 使用CLOUDFLARE代理前请求正常&#xff0c;使用CLOUDFLARE代理请求后出现 原因分析 以下是我的猜测&#xff0c;在默认情况下 CLOUDFLARE代理&#xff0c;可能是直接请求我们服务器的IP&#xff0c;比如&#xff1a;http://1.1.1.1 而不是通过域名的方式&#xff08;如…...

算法随笔_21:字符的最短距离

上一篇:算法随笔_20:区间子数组个数 -CSDN博客 题目描述如下: 给你一个字符串 s 和一个字符 c &#xff0c;且 c 是 s 中出现过的字符。 返回一个整数数组 answer &#xff0c;其中 answer.length s.length 且 answer[i] 是 s 中从下标 i 到离它 最近 的字符 c 的 距离 。 …...

第19个项目:蛇年特别版贪吃蛇H5小游戏

下载地址:https://download.csdn.net/download/mosquito_lover1/90308956 游戏玩法: 点击"开始游戏"按钮开始 使用键盘方向键控制蛇的移动 吃到红色食物可以得分 撞到墙壁或自己会结束游戏 核心源码: class SnakeGame { constructor() { this.canvas = docum…...

Vue3 30天精进之旅:Day01 - 初识Vue.js的奇妙世界

引言 在前端开发领域&#xff0c;Vue.js是一款极具人气的JavaScript框架。它以其简单易用、灵活高效的特性&#xff0c;吸引了大量开发者。本文是“Vue 3之30天系列学习”的第一篇博客&#xff0c;旨在帮助大家快速了解Vue.js的基本概念和核心特性&#xff0c;为后续的深入学习…...

单值二叉树(C语言详解版)

一、摘要 今天要讲的是leetcode单值二叉树&#xff0c;这里用到的C语言&#xff0c;主要提供的是思路&#xff0c;大家看了我的思路之后可以点击链接自己试一下。 二、题目简介 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单…...

贵州端午黔粽探源:贵州味道与黔味文化与糯米的融合?

黔粽的由来? 黔粽的贵州味道?探索贵州“黔味文化”找寻答案! 黔粽的特色由来与贵州味道 贵州粽,简称黔粽。黔粽的主要特色是“酸辣”,以其独特的“酸辣”口味和地域特色,与浙粽、京粽、粤粽、川粽、云粽、闽粽、台湾粽并列为“全国八大粽子派别”之一,并与甜味粽、咸味粽共…...

【Project】CupFox电影网站数据爬取分析与可视化

数据采集清洗与数据存储流程如下图所示。 数据分析与数据可视化流程设计如下 1.使用pymongo从数据库中查询所需的数据。对数据进行处理和分析&#xff0c;进行统计、分类、聚合等操作&#xff0c;提取关键指标和洞察。分析结果可以通过编写Python代码进一步优化、筛选和整理&a…...

Spring Boot 后端跨域解决方案:解锁前后端通信的障碍

随着前后端分离架构的普及&#xff0c;跨域资源共享&#xff08;Cross-Origin Resource Sharing, CORS&#xff09;问题成为了许多开发者必须面对的一个挑战。当Web浏览器尝试从一个源加载资源到另一个不同的源时&#xff0c;出于安全考虑&#xff0c;它会实施同源策略&#xf…...

Linux如何设置用户登录超时(/etc/profile)

Linux如何设置用户登录超时(/etc/profile) 1. 针对所有用户 # vi /etc/profile ... export TMOUT900 # 设置闲置时间为15分钟&#xff0c;单位为秒;如果没有此行则直接添加进去 ... vi /etc/profile TMOUT18000000000000 export QT_IM_MODULEfcitx readonly TMOUT expor…...

Elastic Cloud Serverless 获得主要合规认证

作者&#xff1a;来自 Elastic Oliver Mao 我们很高兴地宣布&#xff0c;Elastic Cloud Serverless 已获得多项重要的合规性认证。这一里程碑加强了我们对安全性、隐私性和法规遵从性的承诺。Elastic Cloud Serverless 现已通过以下行业领先框架的审核或认证&#xff1a;SOC 2 …...

渐变颜色怎么调?

渐变颜色的调整是设计中非常重要的一部分&#xff0c;尤其是在创建具有视觉吸引力和深度感的设计作品时。以下是一些在不同设计软件中调整渐变颜色的详细步骤和技巧&#xff1a; 一、Adobe Photoshop 1. 创建渐变 打开渐变工具&#xff1a; 选择工具栏中的“渐变工具”&#x…...

DDD该怎么去落地实现(1)关键是“关系”

DDD落地的关键是“关系” 这些年&#xff0c;我认为DDD走到了一个死胡同里了&#xff0c;因为落地实现过于困难。很多团队在经过一段时间的学习&#xff0c;清楚理解了DDD那些晦涩的概念&#xff0c;根据业务绘制出领域模型&#xff0c;这都不困难。但绘制领域模型不是我们最终…...

基于本地事务表+MQ实现分布式事务

基于本地事务表MQ实现分布式事务 引言1、原理2、本地消息表优缺点3、本地启动rocketmq4、代码实现及验证4.1、核心代码4.2、代码执行流程4.3、项目结构4.4、项目源码 引言 本地消息表的方案最初由ebay的工程师提出&#xff0c;核心思想是将分布式事务拆分成本地事务进行处理。…...

第17篇:python进阶:详解数据分析与处理

第17篇&#xff1a;数据分析与处理 内容简介 本篇文章将深入探讨数据分析与处理在Python中的应用。您将学习如何使用pandas库进行数据清洗与分析&#xff0c;掌握matplotlib和seaborn库进行数据可视化&#xff0c;以及处理大型数据集的技巧。通过丰富的代码示例和实战案例&am…...

S4 HANA Tax相关的定价过程

本文主要介绍在S4 HANA OP中Tax相关的定价过程相关设置。具体请参照如下内容&#xff1a; 目录 1. 定义定价过程(OBYZ) 2. 将定价过程分配给国家(OBBG)​编辑​编辑 3. 新增Transaction Key(OBCN) 1. 定义定价过程(OBYZ) 定价过程就是为了将“条件类型”和“事务”关联起来…...

Linux下php8安装phpredis扩展的方法

Linux下php8安装phpredis扩展的方法 下载redis扩展执行安装编辑php.ini文件重启php-fpmphpinfo 查看 下载redis扩展 前提是已经安装好redis服务了 php-redis下载地址 https://github.com/phpredis/phpredis 执行命令 git clone https://github.com/phpredis/phpredis.git执行…...

K8S 启动探测、就绪探测、存活探测

先来思考一个问题&#xff1a; 在 Deployment 执行滚动更新 web 应用的时候&#xff0c;总会出现一段时间&#xff0c;Pod 对外提供网络访问&#xff0c;但是页面访问却发生404&#xff0c;这个问题要如何解决呢&#xff1f;学完今天的内容&#xff0c;相信你会有自己的答案。 …...

rust学习-rust中的保留字

rust学习-rust中的保留字 已使用的保留字未来可能使用的保留字 保留字是语言中预定义的标识符&#xff0c;不能用作变量名、函数名或其他自定义标识符&#xff0c;Rust的保留字大致可以分为两类&#xff1a;已使用的保留字和未来可能使用的保留字 已使用的保留字 as&#xff1…...

-bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录

终端报错&#xff1a; -bash: ./uninstall.command: /bin/sh^M: 坏的解释器: 没有那个文件或目录原因&#xff1a;由于文件行尾符不匹配导致的。当脚本文件在Windows环境中创建或编辑后&#xff0c;行尾符为CRLF&#xff08;即回车和换行&#xff0c;\r\n&#xff09;&#xf…...

【C】memory 详解

<memory.h> 是一个 C 标准库头文件&#xff0c;提供了一组内存管理函数&#xff0c;用于分配、释放和操作动态内存。这些函数主要操作的是未初始化的内存块&#xff0c;是早期 C 编程中常用的内存操作工具。 尽管在现代 C 编程中更推荐使用<cstring>或<memory&…...

Android实训九 数据存储和访问

实训9 数据存储和访问 一、【实训目的】 1、 SharedPreferences存储数据; 2、 借助Java的I/O体系实现文件的存储&#xff0c; 3、使用Android内置的轻量级数据库SQLite存储数据; 二、【实训内容】 1、实现下图所示的界面&#xff0c;实现以下功能&#xff1a; 1&#xff…...

Redis vs. 其他数据库:深度解析,如何选择最适合的数据库?

一、如何为项目选择合适的数据库&#xff1f; 选择合适的数据库是一个复杂的过程&#xff0c;需要综合考虑多个因素。下面几个维度来详细阐述&#xff1a; 1.数据模型 关系型数据库&#xff08;RDBMS&#xff09;&#xff1a;适用于高度结构化、关联性强的数据&#xff0c;如电…...

docker 安装 mysql 详解

在平常的开发工作中&#xff0c;我们经常需要用到 mysql 数据库。那么在docker容器中&#xff0c;应该怎么安装mysql数据库呢。简单来说&#xff0c;第一步&#xff1a;拉取镜像&#xff1b;第二步&#xff1a;创建挂载目录并设置 my.conf&#xff1b;第三步&#xff1a;启动容…...

C++实现设计模式---桥接模式 (Bridge)

桥接模式 (Bridge) 桥接模式 是一种结构型设计模式&#xff0c;它通过将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。桥接模式的核心思想是使用组合&#xff08;而非继承&#xff09;来扩展功能。 意图 将抽象部分与实现部分分离&#xff0c;使它们都可以独立地变…...

LangChain + llamaFactory + Qwen2-7b-VL 构建本地RAG问答系统

单纯仅靠LLM会产生误导性的 “幻觉”&#xff0c;训练数据会过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented Generati…...

pycharm 运行远程环境问题 Error:Failed to prepare environment.

问题排查 拿到更详细的报错信息&#xff1a; Help > Diagnostic Tools > Debug Log Settings section: 添加下面的配置 com.intellij.execution.configurations.GeneralCommandLine 重显报错&#xff0c;我这里是再次运行代码打开 Help | Collect Logs and Diagnosti…...

Level2逐笔成交逐笔委托毫秒记录:今日分享优质股票数据20250124

逐笔成交逐笔委托下载 链接: https://pan.baidu.com/s/1UWVY11Q1IOfME9itDN5aZA?pwdhgeg 提取码: hgeg Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交与逐笔委托的详细数据&#xff0c;这种以毫秒为单位的信息能揭示许多关键点&#xff0c;如庄家意图、误导性行为…...

最新最详细的配置Node.js环境教程

配置Node.js环境 一、前言 &#xff08;一&#xff09;为什么要配置Node.js&#xff1f;&#xff08;二&#xff09;NPM生态是什么&#xff08;三&#xff09;Node和NPM的区别 二、如何配置Node.js环境 第一步、安装环境第二步、安装步骤第三步、验证安装第四步、修改全局模块…...

【Address Overfitting】解决过拟合的三种方法

目录 1. 收集更多数据实践方法&#xff1a;适用场景&#xff1a;优缺点&#xff1a; 2. 特征选择方法介绍&#xff1a;实践示例&#xff1a;适用场景&#xff1a;优缺点&#xff1a; 3. 正则化&#xff08;Regularization&#xff09;正则化类型&#xff1a;实践示例&#xff1…...

【缘于J2ME】

我与 J2ME 的不解之缘 那年我 25 岁&#xff0c;如今已即将退休。 在那个娱乐生活并不丰富的年代&#xff0c;每每响起「小霸王其乐无穷啊」&#xff0c;小伙伴们就会摩拳擦掌、轮番上阵&#xff0c;而我却痴迷于 G-BASIC 编程。 最大的乐趣就是对着仅有的两页说明&#xff0c…...

c#使用log4Net配置日志文件

1.# 写一个通用类 LogHelper using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using log4net;namespace WindowsFormsApplication22 {public class LogHelper{static ILog mylog LogManager.GetLogge…...

[ACTF2020 新生赛]Include1

题目 点击tips后&#xff1a; 使用PHP伪协议直接读取flag /?filephp://filter/readconvert.base64-encode/resourceflag.php base64解码 拿下flag flag{6cce5a3d-997a-4c8a-ba07-f6652ee462a9}...

【数据结构】树的基本:结点、度、高度与计算

树是数据结构中一种重要的非线性结构&#xff0c;广泛应用于计算机科学的各个领域&#xff0c;例如文件系统、数据库索引、编译器等。理解树的各种性质&#xff0c;如结点数、度、高度等&#xff0c;对于解决实际问题至关重要。 本文将会探讨树的基本概念&#xff0c;以及给出几…...

1.24 共享内存和信号灯集

使用共享内存信号灯集实现两个进程之间相互对话。 程序代码&#xff1a; #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stst.h> #include <fcntl.h> #…...

正则表达式以及Qt中的使用

目录 一、正则表达式 1、基本匹配&#xff1a; 2、元字符&#xff1a; 2.1 .运算符&#xff1a; 2.2 字符集&#xff1a; 2.3 重复次数&#xff1a; 2.4 量词{} 2.5 特征标群() 2.6 或运算符 2.7 \反斜线转码特殊字符 2.8 锚点 3、简写字符 4、零宽度断言 4.1 正…...

STM32简介

STM32简介 STM32是ST公司基于ARMCortex-M内核开发的32位微控制器 &#xff08;Microcontroller&#xff09; MCU微控制器、MPU微处理器、CPU中央处理器 1.应用领域 STM32常应用于嵌入式领域。 如智能车&#xff1a;循迹小车 读取光电传感器或者摄像头的数据&#xff0c;…...

【设计模式-行为型】访问者模式

一、什么是访问者模式 说起来访问者模式&#xff0c;其实很少用。我一直在思考该用什么样的例子把这个设计模式表述清晰&#xff0c;最近突然想到一个例子也许他就是访问者。港片有过很辉煌的年代&#xff0c;小的时候一直在看港片觉得拍的非常好&#xff0c;而且演员的演技也在…...

上海亚商投顾:沪指冲高回落 大金融板块全天强势 上海亚商投

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一&#xff0e;市场情绪 市场全天冲高回落&#xff0c;深成指、创业板指午后翻绿。大金融板块全天强势&#xff0c;天茂集团…...

docker部署jenkins

环境&#xff1a; centos7.9 jenkins/jenkins:lts-jdk11 1、拉去jenkins镜像&#xff0c;请指明版本号 [rootlocalhost ~]# docker pull jenkins/jenkins:lts 开始拉取 拉取完成 [rootlocalhost ~]# docker pull jenkins/jenkins:lts lts: Pulling from jenkins/jenkins 0a9…...

初阶数据结构:链表(二)

目录 一、前言 二、带头双向循环链表 1.带头双向循环链表的结构 &#xff08;1)什么是带头&#xff1f; (2)什么是双向呢&#xff1f; &#xff08;3&#xff09;那什么是循环呢&#xff1f; 2.带头双向循环链表的实现 &#xff08;1&#xff09;节点结构 &#xff08;2…...

Django实现数据库的表间三种关系

Django实现数据库的表间三种关系 1. 一对多&#xff08;One-to-Many&#xff09;关系示例&#xff1a;关系说明&#xff1a;查询示例&#xff1a; 2. 一对一&#xff08;One-to-One&#xff09;关系示例&#xff1a;关系说明&#xff1a;查询示例&#xff1a; 3. 多对多&#x…...

AI导航工具我开源了利用node爬取了几百条数据

序言 别因今天的懒惰&#xff0c;让明天的您后悔。输出文章的本意并不是为了得到赞美&#xff0c;而是为了让自己能够学会总结思考&#xff1b;当然&#xff0c;如果有幸能够给到你一点点灵感或者思考&#xff0c;那么我这篇文章的意义将无限放大。 背景 随着AI的发展市面上…...

概率密度函数(PDF)分布函数(CDF)——直方图累积直方图——直方图规定化的数学基础

对于连续型随机变量&#xff0c;分布函数&#xff08;Cumulative Distribution Function, CDF&#xff09;是概率密度函数&#xff08;Probability Density Function, PDF&#xff09;的变上限积分&#xff0c;概率密度函数是分布函数的导函数。 如果我们有一个连续型随机变量…...

OpenHarmony OTA升级参考资料记录

OpenHarmony 作为一个开源分布式操作系统,通过其强大的 OTA(Over-The-Air)升级能力,为开发者和厂商提供了一套灵活而安全的系统升级方案。 OTA升级方式 根据升级包的应用方式,OpenHarmony 的 OTA 升级可以分为两种:本地升级和网络OTA升级。 本地升级 本地升级是将已制作…...

从 Spark 到 StarRocks:实现58同城湖仓一体架构的高效转型

作者&#xff1a;王世发&#xff0c;吴艳兴等&#xff0c;58同城数据架构部 导读&#xff1a; 本文介绍了58同城在其数据探查平台中引入StarRocks的实践&#xff0c;旨在提升实时查询性能。在面对传统Spark和Hive架构的性能瓶颈时&#xff0c;58同城选择StarRocks作为加速引擎&…...

网络知识小科普--5

81、什么是组播路由? 组播路由是一种有针对性的广播形式&#xff0c;将消息发送到所选择的用户组&#xff0c;而不是将其发送到子网上的所有用户。 82、加密在网络上的重要性是什么? 加密是将信息转换成用户不可读的代码的过程。然后使用秘密密钥或密码将其翻译或解密回其…...

【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HS、RS、ES 和 ED 签名与验签 签名方式算法密钥类型签名要点验签要点HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名- 将 header.payload 作为数据输入- 使用同一密钥重新计算 HMAC 签名- 比较计算结果与接收到的签名是否一致RSRSA-SHA256公钥 …...

cherry USB 键盘分析

文章目录 cherry USB 键盘分析描述符结构设备描述符配置描述符集合配置描述符接口 1 描述符HID 描述符端点 IN 描述符接口 2 描述符HID 描述符端点 IN 描述符端点 OUT 描述符字符串描述符语言 ID (字符串索引为 0)厂商字符串(字符串索引为 1)产品字符串(字符串索引为 2)HID 报告…...

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…...