学期2024-2025-1 学号20241317 《计算机基础与程序设计》第十三周学习总结

学期2024-2025-1 学号20241317 《计算机基础与程序设计》第十三周学习总结

作业信息

这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计
这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)
这个作业的目标 <写上具体方面>
作业正文 https://www.cnblogs.com/manurios/p/18622472

教材学习内容总结

在《C语言程序设计》教材中,第十二章通常会介绍结构体以及基于结构体构建的简单数据结构。以下是这一章节可能包含的内容总结:

结构体(Structures)

  • 结构体定义:介绍如何使用struct关键字定义结构体类型,包括如何声明结构体变量。
  • 结构体初始化:讲解如何初始化结构体变量,包括直接初始化和使用memset()函数进行初始化。
  • 结构体访问:使用.运算符访问结构体成员,以及如何通过指针访问结构体成员(使用->运算符)。
  • 结构体数组:创建和操作结构体数组,包括如何遍历和处理结构体数组。
  • 结构体与函数:如何将结构体作为参数传递给函数,以及如何从函数返回结构体。
  • 结构体嵌套:介绍结构体中可以嵌套其他结构体,以及如何访问嵌套结构体的成员。

枚举类型(Enumerations)

  • 枚举定义:使用enum关键字定义枚举类型,以及如何声明枚举变量。
  • 枚举使用:讲解如何使用枚举类型来表示一组相关的常量,提高代码的可读性和可维护性。

联合体(Unions)

  • 联合体定义:介绍如何使用union关键字定义联合体类型,以及如何声明联合体变量。
  • 联合体使用:讲解联合体的特性,即所有成员共享同一块内存空间,以及如何根据需要访问不同的成员。

数据结构基础

  • 链表(Linked List)
    • 单链表:介绍单链表的基本概念,包括节点的定义和链表的创建。
    • 链表操作:讲解如何实现链表的插入、删除、查找等基本操作。
  • 栈(Stack)
    • 栈的定义:介绍栈的后进先出(LIFO)特性。
    • 栈的实现:使用数组或链表实现栈,并实现栈的基本操作,如pushpoppeek等。
  • 队列(Queue)
    • 队列的定义:介绍队列的先进先出(FIFO)特性。
    • 队列的实现:使用数组或链表实现队列,并实现队列的基本操作,如enqueuedequeuefront等。
  • 树(Tree)
    • 树的定义:介绍树的基本概念,包括节点、边、根节点、叶子节点等。
    • 二叉树:讲解二叉树的定义,以及如何使用结构体表示二叉树的节点。
    • 二叉树遍历:介绍二叉树的三种基本遍历方法:前序遍历、中序遍历和后序遍历。

应用实例

  • 结构体在实际问题中的应用:通过一些实际问题,展示如何使用结构体来组织和管理数据。
  • 数据结构的应用:通过实例讲解如何使用链表、栈、队列等数据结构解决实际问题,如栈在表达式求值中的应用、队列在任务调度中的应用等。

这一章节的内容旨在帮助读者掌握结构体的使用方法,并通过结构体构建简单的数据结构,为后续更复杂的数据结构和算法学习打下基础。

教材学习中的问题和解决过程(先问 AI)

(一个模板:我看了这一段文字 (引用文字),有这个问题 (提出问题)。 我查了资料,有这些说法(引用说法),根据我的实践,我得到这些经验(描述自己的经验)。 但是我还是不太懂,我的困惑是(说明困惑)。【或者】我反对作者的观点(提出作者的观点,自己的观点,以及理由)。 )

  • 问题1:结构体定义注意事项有什么?
  • 问题1解决方案:在C语言中定义结构体时,需要注意以下几点:

1. 结构体名称

  • 命名规范:结构体类型名称应遵循良好的命名规范,通常使用大写字母开头或全大写字母,并使用下划线分隔单词,例如StudentSTUDENT_INFO
  • 避免与关键字冲突:确保结构体名称不与C语言的关键字或已定义的标识符冲突。
  • 描述性名称:选择能够清晰描述结构体内容和用途的名称,使代码更易读和理解。

2. 成员变量

  • 类型选择:根据实际需求为成员变量选择合适的数据类型,例如使用int表示整数、floatdouble表示浮点数、char数组表示字符串等。
  • 成员命名:为成员变量选择有意义的名称,通常使用小写字母开头,并使用下划线分隔单词,例如nameagescore等。
  • 避免重复成员:确保结构体中没有重复的成员变量,每个成员变量应具有独特的功能和用途。
  • 对齐和填充:了解结构体成员的对齐和填充规则,不同编译器和平台可能有不同的对齐要求,这可能会影响结构体的内存占用和性能。

3. 结构体初始化

  • 初始化方式:在定义结构体变量时,可以使用初始化列表对成员变量进行初始化,例如:
    struct Student stu = {"John", 20, 85.5};
    
  • 默认初始化:如果未显式初始化,结构体的成员变量可能会被初始化为零或随机值,具体取决于编译器和平台。

4. 结构体嵌套

  • 嵌套结构体:结构体中可以嵌套其他结构体,但要注意嵌套的层次不宜过深,以保持代码的清晰和可维护性。
  • 嵌套访问:访问嵌套结构体的成员时,需要使用多个.运算符,例如:
    struct Address address = {"China", "Beijing"};
    struct Student stu = {"John", 20, address};
    printf("%s\n", stu.address.city);
    

5. 结构体与指针

  • 结构体指针:可以使用指针访问结构体变量,使用->运算符访问成员变量,例如:
    struct Student *p = &stu;
    printf("%s\n", p->name);
    
  • 动态分配结构体:可以使用malloc()等函数动态分配结构体内存,但要注意内存的释放和指针的管理。

6. 结构体与函数

  • 函数参数:将结构体作为函数参数传递时,可以传递结构体变量或结构体指针,根据需要选择传值或传址。
  • 返回结构体:函数可以返回结构体变量,但要注意大结构体的返回可能会导致性能开销。

7. 结构体与内存管理

  • 内存占用:了解结构体的内存占用情况,包括成员变量的大小和对齐填充的影响。
  • 内存释放:如果结构体中包含指向动态分配内存的指针,需要在适当的时候释放这些内存,避免内存泄漏。

通过注意这些事项,可以更好地定义和使用结构体,提高程序的可读性、可维护性和性能。

  • 问题2:如何实现链表的位置转换?
  • 问题2解决方案:在链表中实现位置交换,通常是指交换两个节点在链表中的位置。以下是实现链表位置交换的一般步骤和注意事项:

单链表节点交换

假设我们有一个单链表,每个节点包含数据和指向下一个节点的指针。我们需要交换两个节点node1node2的位置。以下是实现步骤:

1. 定义链表节点结构体

typedef struct ListNode {
    int data;
    struct ListNode *next;
} ListNode;

2. 查找节点及其前驱节点

  • 首先,需要找到node1node2以及它们的前驱节点prev1prev2
  • 如果node1node2是头节点,那么它们的前驱节点可以是NULL

3. 交换节点

  • 根据node1node2的位置关系,以及它们是否相邻,分别处理不同的情况:
    • 如果node1node2相邻,交换它们的next指针。
    • 如果node1node2不相邻,需要调整它们的前驱节点的next指针,以及node1node2next指针。

4. 处理特殊情况

  • 如果node1node2是尾节点,需要特别注意尾节点的处理。
  • 如果链表只有一个节点或两个节点相同,不需要进行交换。

示例代码

以下是一个简单的示例代码,展示如何交换两个节点的位置:

void swapNodes(ListNode **head, ListNode *node1, ListNode *node2) {
    if (node1 == node2) {
        return; // 相同节点,无需交换
    }

    ListNode *prev1 = NULL, *prev2 = NULL;
    ListNode *current = *head;

    // 查找node1的前驱节点
    while (current && current->next != node1) {
        prev1 = current;
        current = current->next;
    }

    // 查找node2的前驱节点
    current = *head;
    while (current && current->next != node2) {
        prev2 = current;
        current = current->next;
    }

    // 如果没有找到node1或node2,无法交换
    if (!node1 || !node2) {
        return;
    }

    // 处理node1和node2的前驱节点
    if (prev1) {
        prev1->next = node2;
    } else {
        *head = node2; // node1是头节点
    }

    if (prev2) {
        prev2->next = node1;
    } else {
        *head = node1; // node2是头节点
    }

    // 交换node1和node2的next指针
    ListNode *temp = node1->next;
    node1->next = node2->next;
    node2->next = temp;
}

注意事项

  • 边界条件:确保处理好头节点和尾节点的特殊情况。
  • 相邻节点:如果两个节点相邻,交换时要注意不要丢失链表的连接。
  • 内存管理:在交换过程中,不要丢失对节点的引用,确保链表的完整性和连续性。
  • 效率考虑:在实际应用中,频繁的节点交换可能会导致链表操作的效率降低,需要根据具体需求进行优化。

通过上述步骤和示例代码,可以在单链表中实现节点的位置交换。对于双向链表,交换过程类似,但需要同时调整前驱和后继指针。

  • ...

基于AI的学习

问题1:举例机构体和联合体的区别:
结构体(struct)和联合体(union)都是C语言中用于组合多个不同类型的数据项的复合类型,但它们在内存分配和使用方式上有显著的区别。以下是结构体和联合体的区别举例:

结构体(struct

  • 内存分配:结构体为每个成员变量分配独立的内存空间。结构体的总大小等于其所有成员变量大小的总和(考虑内存对齐)。
  • 成员访问:可以同时访问结构体的所有成员变量,每个成员变量都有自己的内存地址。
  • 使用场景:适用于需要存储多个相关数据项的场景,例如表示一个学生的信息(姓名、年龄、成绩等)。

结构体示例

#include <stdio.h>

// 定义一个学生结构体
typedef struct {
    char name[50];
    int age;
    float score;
} Student;

int main() {
    // 创建并初始化一个学生结构体变量
    Student stu = {"John Doe", 20, 85.5};

    // 访问和打印结构体成员
    printf("Name: %s\n", stu.name);
    printf("Age: %d\n", stu.age);
    printf("Score: %.2f\n", stu.score);

    return 0;
}

联合体(union

  • 内存分配:联合体为所有成员变量分配同一块内存空间。联合体的大小等于其最大成员变量的大小。
  • 成员访问:同一时间只能使用联合体的一个成员变量,因为所有成员共享同一块内存。
  • 使用场景:适用于需要根据不同的情况存储不同类型的数据的场景,例如表示一个可以存储整数或浮点数的变量。

联合体示例

#include <stdio.h>

// 定义一个可以存储整数或浮点数的联合体
typedef union {
    int intValue;
    float floatValue;
} Number;

int main() {
    // 创建一个联合体变量
    Number num;

    // 存储整数
    num.intValue = 100;
    printf("Integer Value: %d\n", num.intValue);

    // 存储浮点数
    num.floatValue = 3.14;
    printf("Float Value: %.2f\n", num.floatValue);

    return 0;
}

总结

  • 内存使用:结构体使用更多的内存,因为每个成员都有独立的内存空间;联合体使用较少的内存,因为所有成员共享同一块内存。
  • 数据访问:结构体可以同时访问所有成员;联合体同一时间只能访问一个成员。
  • 适用场景:结构体适用于存储多个相关数据项;联合体适用于根据需要存储不同类型的数据。

通过这些区别和示例,可以更好地理解结构体和联合体在C语言中的不同用途和使用方式。
问题2:如何查找链表?
在链表中查找特定的节点通常涉及遍历链表,直到找到符合条件的节点。查找操作是链表操作中的基本操作之一,以下是一些常见的查找方法和示例:

单链表查找

假设我们有一个单链表,每个节点包含数据和指向下一个节点的指针。我们需要查找包含特定值的节点。

定义链表节点结构体

typedef struct ListNode {
    int data;
    struct ListNode *next;
} ListNode;

查找特定值的节点

ListNode* findNode(ListNode *head, int value) {
    ListNode *current = head; // 从头节点开始遍历
    while (current != NULL) {
        if (current->data == value) {
            return current; // 找到节点,返回节点指针
        }
        current = current->next; // 移动到下一个节点
    }
    return NULL; // 遍历结束,未找到节点
}

双向链表查找

双向链表的查找与单链表类似,但由于每个节点都有前驱和后继指针,可以双向遍历。但通常情况下,查找操作仍然从头节点开始向后遍历。

定义双向链表节点结构体

typedef struct DoublyListNode {
    int data;
    struct DoublyListNode *prev;
    struct DoublyListNode *next;
} DoublyListNode;

查找特定值的节点

DoublyListNode* findNode(DoublyListNode *head, int value) {
    DoublyListNode *current = head;
    while (current != NULL) {
        if (current->data == value) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

循环链表查找

循环链表的查找也需要遍历链表,但由于链表是循环的,需要注意避免无限循环。

定义循环链表节点结构体

typedef struct CircularListNode {
    int data;
    struct CircularListNode *next;
} CircularListNode;

查找特定值的节点

CircularListNode* findNode(CircularListNode *head, int value) {
    if (head == NULL) {
        return NULL;
    }
    CircularListNode *current = head;
    do {
        if (current->data == value) {
            return current;
        }
        current = current->next;
    } while (current != head); // 循环直到回到头节点
    return NULL;
}

查找节点的前驱节点

在某些情况下,可能需要找到某个节点的前驱节点,例如在删除节点时。

查找特定值节点的前驱节点

ListNode* findPreviousNode(ListNode *head, int value) {
    if (head == NULL || head->next == NULL) {
        return NULL;
    }
    ListNode *current = head;
    while (current->next != NULL) {
        if (current->next->data == value) {
            return current; // 返回前驱节点
        }
        current = current->next;
    }
    return NULL; // 未找到
}

注意事项

  • 边界条件:在查找过程中,要特别注意链表为空或只有一个节点的情况。
  • 效率:查找操作的时间复杂度为O(n),其中n是链表的长度。对于大型数据集,查找效率可能较低,可以考虑使用其他数据结构(如哈希表)来提高查找效率。
  • 循环链表:在循环链表中查找时,要确保不会无限循环,通常通过检查当前节点是否回到头节点来结束循环。

通过这些方法和示例,可以在不同类型的链表中实现查找操作。

三个原则:

  • 切勿原封不动地接受生成式人工智能工具的输出;确保对其进行评估、完善和修改(或提示),以适应您的目标。
  • 切勿将任何个人数据(自己、同学、老师等)或版权材料纳入到你的提示词中。这个可以说是保护个人隐私的最起码的举措。
  • 所有人工智能生成工具都容易产生幻觉,因此会生成不准确或误导性的信息,要学会甄别信息真假

选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容

“我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问题”

核心是要求GPT:“请你以苏格拉底的方式对我进行提问”

然后GPT就会给你提问,如果不知道问题的答案,可以反问AI:“你的理解(回答)是什么?”

如果你觉得差不多了,可以先问问GPT:“针对我XXX知识点,我理解了吗?”

GPT会给出它的判断,如果你也觉得自己想清楚了,可以最后问GPT:“我的回答结束了,请对我的回答进行评价总结”,让它帮你总结一下。

代码调试中的问题和解决过程

  • 问题1:XXXXXX
  • 问题1解决方案:XXXXXX
  • 问题2:XXXXXX
  • 问题2解决方案:XXXXXX
  • ...

代码托管

(statistics.sh脚本的运行结果截图)

上周考试错题总结

  • 错题1及原因,理解情况
  • 错题2及原因,理解情况
  • ...

其他(感悟、思考等,可选)

xxx
xxx

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 300/500 2/4 18/38
第三周 500/1000 3/7 22/60
第四周 300/1300 2/9 30/90

尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

参考:软件工程软件的估计为什么这么难软件工程 估计方法

  • 计划学习时间:XX小时

  • 实际学习时间:XX小时

  • 改进情况:

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料

posted @ 2024-12-22 20:18  manurios  阅读(7)  评论(0编辑  收藏  举报