【结尾ending】

9.27

按位运算

按位取与-&

两个位上两个都是必须都是1 结果才是1,否则结果为0;

常用
1️⃣.让某一位或某些位为0:x& 0xFE
2️⃣.取一个数中的一段:x& 0xFF
在这里插入图片描述
FE⬆️ 使另一个数最低位变成0;

按位取或-I

两个位上有一个是一 结果就为1 否则结果就为0;
常用
使一位或几位为1:xI 0x01(希望最后那位数上的比特是1 用±做不到)
把两个数拼起来:0x00FF I 0xFF00(结果为四个F)
在这里插入图片描述
FE⬆️;取或:只要对应位上有1的它就是1

按位取反-~

把每个比特位从1变成0,从0变成1(与算补码不同)每个比特取反(每个位)!!
在这里插入图片描述

  • 想得到全部位为1的数:~0
  • 7的二进制是0111,x I 7 使得低三位为1,而x&~7使得低三位为0.

逻辑运算VS按位运算

  • 逻辑运算只看到两个值(0、1)
  • so可以认为逻辑运算相当于把所有非零值都变成1 然后做按位运算
  • 5&4——>而5&&4——>1&1——>1
  • 5 I 4——>5 而5 II4——>1I1 ——>1
  • ~4——>3而!4——>!1——>0
按位异或^
  • 两个位相等,结果为0;两个位不相等,结果为1.
  • 如果x=y,则x^y=0;
  • 对同一个变量用同一个值异或两次,等于什么也没做
  • xyy ——> x

移位运算

左移<<
  • i << j
  • i中所有的位向左移动j个位置,而右边留下的空位置填入0;
  • 所有<int的类型,移位以int的方式来做,结果是int
  • x <<= 1等价于x *= 2^n(最多移动的位数取决于你的int有多大)
右移>>
  • i中所有位向右移j位
  • 所有小于int的类型,移位以int的方式来做,结果是int
  • 对于unsigned的类型,左边填0
  • 对signed的类型,左边填原来的最高位(保持符号不变)
  • x >>=1等价于 x /= 2^n
  • x >>= n等价于 x /= 2^n

移位的位数不要用负数,这是没有定义的行为,如:x<< -2(✖)

位段

  • 把一个int的若干位组成一个结构
    取地址再解指针,实际上传入的是数(一个struct把它当成一个int来做些事情):
    在这里插入图片描述
    定义了一个位段之后:

  • 可直接用位段的成员名来访问

  • 比移位、与、或方便

  • 编译器会安排其中的位的排列,不具有可移植性

  • 当所需求位超过一个int时 会采用多个int(大小端的问题)

可变数组

  • 可增长
  • 获取当前大小
  • 访问元素 单元
能提供 能增长能变大小的数组:

Arrayarray_create(int init_size);
void array_free(Array *a);
int array_size(const Array a);
int
array_at(Array *a,int index);
void array_inflate(Array *a,int more_size);

array 表示用来创建这个数组
free 把该数组回收
size 数组里面有哪些单元可以用
at 获得并访问数组中的某个单元(可以读可以写 可作左值也可以作右值)
inflate 让该数组长大

返回一个结构体 使得我们在外面可以比较灵活使用这个array_create返回的 制造出来的那个array

可变数组的数据访问

封装:
在这里插入图片描述

返回值是指针 解引用后的返回值可以赋值!方便通过指针转入值(听不太懂。。。)

可变数组的自动生长

本malloc里面出来的东西不可自动生长
so要重新去申请一块新的空间,然后把老空间的东西用循环复制到新的空间去,扩大一次=遍历一次数组,扩容n个容量,来保证程序运行的效率

如果直接加BLOCK_SIZE,那么只要index<size数组都会增长,比如index101到120时数组会增长20次,但这期间需要增长一次就够了

在这里插入图片描述
inflate函数需要的参数是需要扩展的空间的大小,所以才减去a->size,前面那些算出来的是index所在block块的总体的大小

可变数组的缺陷

每次膨胀时分配新内存是一种简单、干净的方法,但复制需要时间,而且在内存受限的情况下可能会失败
在这里插入图片描述

申请更大块内存然后被free 回收
主要是先申请后释放的问题,如果先释放,就没法进行数据迁移了。不严格的讲只能储存到计算机内存一半的数据,因为旧数据是复制后再删除。because要先申请新的空间再释放掉之前的。
so这个方法不够高效,需要用到链表连接起来!⬇️

链表

图解:

在这里插入图片描述

结点把它定义成一个结构
不是递归,就是结构体里定义了一个指向这种结构体的指针
自己调用自己
在这里插入图片描述

Node* createList()
 {
    return NULL; // 返回空指针表示空链表
 }

插入节点:
(头)

Node* insertAtHead(Node* head, int data)
 {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 动态分配内存
    newNode->data = data;
    newNode->next = head; // 新节点指向原链表的头
    return newNode; // 返回新的头指针
}

(尾)

Node* insertAtTail(Node* head, int data) 
{
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;

    if (head == NULL)
     {
        return newNode; // 如果链表为空,返回新节点
    }

    Node* temp = head;
    while (temp->next != NULL)
     {
        temp = temp->next; // 遍历到链表的最后一个节点
    }
    temp->next = newNode; // 将新节点添加到尾部
    return head; // 返回头指针
}
链表的函数

×
在这里插入图片描述

1.函数传递参数的方式是直接创建一个相等类型的变量
2.这意味着函数内的“head”是一个新指针指向主函数内同一地址
3.但是并不知道主函数内head的地址(即指针的地址)

👆传进去的是地址,但是我们要改变的是地址,所以要用地址的地址
它要修改的是指针(head=p),而不是指针所指向的结构体,所以要传入head的地址,函数传入head参数,函数会在函数块内创造一个新的指针变量head,改变内部的head,main中的head不会改变。我们平时用的指针都是指向某一个变量的,指针传入函数里面实际上只是同名指针指向地址相同,但是这里指向的是NULL,而不是变量,所以实际上是不一样的,指针就是指地址,你传入head这个地址,但是在add函数中要把传进来的地址换掉,而不是改掉访问地址的值

链表的搜索

搜索链表中是否存在某个值:

Node* search(Node* head, int value)
 {
    Node* current = head;
    while (current != NULL) 
    {
        if (current->data == value) 
        {
            return current; // 找到值,返回对应节点
        }
        current = current->next; // 继续遍历
    }
    return NULL; // 未找到,返回NULL
}

链表的删除

删除链表中指定值的节点:

Node* deleteNode(Node* head, int value) 
{
    if (head == NULL) return NULL; // 链表为空

    if (head->data == value) { // 删除头节点
        Node* temp = head->next;
        free(head); // 释放内存
        return temp; // 返回新的头指针
    }

    Node* current = head;
    while (current->next != NULL && current->next->data != value)
    {
        current = current->next; // 遍历链表
    }

    if (current->next != NULL) 
    { // 找到节点
        Node* temp = current->next;
        current->next = temp->next; // 断开连接
        free(temp); // 释放内存
    }
    return head; // 返回头指针
}
链表的清除

释放链表中所有节点的内存:

void clearList(Node* head) 
{
    Node* current = head;
    Node* temp;

    while (current != NULL)
    {
        temp = current;
        current = current->next; // 先保存下一个节点
        free(temp); // 释放当前节点内存
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值