C语言结构体学习总结

知识体


1.struct定义

struct S{
    int a;
    char b;
    float c;
}s1;

通常是struct 结构体名称 { 变量 } 结构体变量 ;

假如出现

struct {
    int a;
    char b;
    float c;
}S;

这种情况其实也是定义为S结构体


2.typedef使用

typedef是用来重新定义一个数据类型为另一个名称(不止可以用于结构体):

typedef struct s1{
    ~~~
}TT;

这个实际上是将struct s1别名为TT;

在C++中无需这样操作,直接s1 变量名 ,就能定义一个这种结构体变量。

而在C中则需要利用typedef为struct s1取别名为TT,也就是"TT" = "struct s1",效果相同。(即struct s1 变量名 等效于 TT s变量名)


3.union联合体

存在的意义:结构体所占内存即所有类型所占字节总和,但有时候我们只想利用其中单个变量,对于其他变量则在不需要调用。如果用结构体定义一个变量组,就可能会造成不必要的资源浪费。

为了使这种需求实现且减少资源浪费,利用union联合体即可。

union用法:定义与结构体类似

union S{
    int a;
    char b;
    float c;
}s1;

这个union联合体所占内存即最大变量所占内存,即所有变量共用同一个内存

  • char 通常占 1 个字节。
  • int 的大小通常为 4 个字节(32 位系统)或 8 个字节(64 位系统)。
  • float 通常占 4 个字节。

即S所占内存为4字节; 

****注意!!:

union联合体中进行赋值操作时会对这个内存进行赋值操作

这里将s1.a赋值后,即对整个s1所对应的值进行了赋值,字符类变量b转换成为对应的ascll值。

即整体赋值。


4.链表

链表与数组都是基本的数据结构,根本区别在于调用内存的方式

前者为:动态分配                后者为:手动分配

1.对比

数组的特点:

  1. 在内存中,数组是一块连续的区域。
  2. 数组需要预留空间,在使用前需要提前申请所占内存的大小,这样不知道需要多大的空间,就预先申请可能会浪费内存空间,即数组空间利用率低。
  3. 在数组起始位置处,插入数据和删除数据效率低。插入数据时,待插入位置的的元素和它后面的所有元素都需要向后搬移。删除数据时,待删除位置后面的所有元素都需要向前搬移。
  4. 随机访问效率很高,时间复杂度可以达到O(1)。因为数组的内存是连续的,想要访问那个元素,直接从数组的首地址处向后偏移就可以访问到了。
  5. 数组开辟的空间,在不够使用的时候需要扩容,扩容的话,就会涉及到需要把旧数组中的所有元素向新数组中搬移。
  6. 数组的空间是从栈分配的。

链表的特点:

  1. 在内存中,元素的空间可以在任意地方,空间是分散的,不需要连续。
  2. 链表中的元素都会两个属性,一个是元素的值,另一个是指针,此指针标记了下一个元素的地址。每一个数据都会保存下一个数据的内存的地址,通过此地址可以找到下一个数据。
  3. 查找数据时效率低,时间复杂度为O(N)。因为链表的空间是分散的,所以不具有随机访问性,如要需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度达到O(N)。
  4. 空间不需要提前指定大小,是动态申请的,根据需求动态的申请和删除内存空间,扩展方便,故空间的利用率较高。
  5. 任意位置插入元素和删除元素效率较高,时间复杂度为O(1)。
  6. 链表的空间是从堆中分配的。

总结:

  • 对于想要快速访问数据,不经常有插入和删除元素的时候,选择数组。
  • 对于需要经常的插入和删除元素,而对访问元素时的效率没有很高要求的话,选择链表。

以上内容以New Bing总结于数组和链表的区别_链表和数组的区别-CSDN博客面试题解答系列:数组和链表的区别 - 知乎

2.定义

链表定义是以结构体为基础创建的通常为

struct ListNode {
    int data;           // 数据域
    ListNode *next;     // 指向下一个节点的指针
};

这个结构体要有数据域与指向下个节点的指针

静态链表:

struct ListNode s1, s2, s3, *head, *p;
        head = &s1;
        scanf("%d,%d,%d", &s1.data, &s2.data, &s3.data);
        s1.next = &s2;
        s2.next = &s3;
        s3.next = NULL;
        p = head;
    do {
        printf("%d", p->data);
        p = p->next;
    } while (p != NULL);

动态链表:(两数之和-Leetcode

typedef struct  {
      int val;//值
      ListNode *next;//指向下个节点的指针
}ListNode;

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *head=nullptr,*tail=nullptr;
        int carry=0;
        while(l1||l2) //循环直到l1与l2都为空指针
        {
            int n1=l1?l1->val:0; //不为空指针即执行赋值为l1中的值
            int n2=l2?l2->val:0;
            int sum=n1+n2+carry;
            if(!head){//head 为空指针执行
                head=tail=new ListNode(sum%10);
            }
            else{
                tail->next=new ListNode(sum%10);
                tail=tail->next;
            }
            carry=sum/10;
            if(l1){
                l1=l1->next;
            }
            if(l2){
                l2=l2->next;
            }
        }
        if(carry>0){
            tail->next=new ListNode(carry);
        }
        return head;
    }

流程:

  1. 首先,定义了一个名为 ListNode 的结构体,它有一个整数 val 和一个指向下一个 ListNode 的指针 next

  2. addTwoNumbers 函数接收两个 ListNode 指针 l1 和 l2 作为参数,这两个指针分别指向两个链表的头部。

  3. 在函数内部,定义了两个 ListNode 指针 head 和 tail,以及一个名为 carry 的整数,用于存储进位。

  4. 然后,进入一个循环,只要 l1 或 l2 中有一个不是空指针,就会继续循环。在每次循环中,首先计算 l1 和 l2 当前节点的值(如果对应的指针不是空的话)以及进位 carry 的和。

  5. 如果 head 是空指针,那么就创建一个新的 ListNode,其值为 sum 10 取余的结果,并将 head 和 tail 都指向这个新节点。

  6. 如果 head 不是空指针,那么在 tail 后面添加一个新的 ListNode,其值也是 sum 对 10 取余的结果,并更新 tail 为新添加的节点。

  7. 更新 carry 为 sum 除以 10 的结果。

  8. 如果 l1 或 l2 不是空指针,那么将它们更新为指向下一个节点。

  9. 在循环结束后,如果 carry 大于 0,那么在 tail 后面添加一个新的 ListNode,其值为 carry

  10. 最后,函数返回 head,即结果链表的头部。

  • 32
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值