C语言学习笔记(浙大翁恺版)第十四周 链表

目录

14.1.1 可变数组

array.h

array.c

array.c main

14.2.1 可变数组的缺陷(2个)

14.2.2 链表

Node.h

linked-list.c

14.2.3 链表的函数

方法一:错误的示例

方法二:有关最后的head = p; 

方法三:传head的指针进去 

方法四:创建一个List结构体代表整个链表

14.2.4 链表的一些操作

遍历链表

搜索链表(在搜索基础上更进一步)

链表删除(搜索到了才能删除)

清空链表


14.1.1 可变数组

首先我们想一想这个问题需要的特点(功能):

  • 可增长
  • 能获得当前大小
  • 可以访问其中的单元

解决方法:设立函数库,几个函数分别实现不同功能

array.h

#ifndef _ARRAY_H
#define _ARRAY_H

typedef struct{
    int *array;
    int size;
}Array;//重命名结构为ARRAY

}*Array
很多人第三方库会设定成一个指针,下方的参数表里经常用到,
可以将参数表里的*去掉了,但是这样的坏处是你之后就不能访问
本地变量array(会动态创建一个),而且可读性也不好

Array array_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.c

#include"array.h"

//typedef struct{
//    int *array;
//    int size;
//}Array;

const BLOCK_SIZE = 20;//设自己觉得合适的大小

Array array_create(int init_size)
{
    Array a;//创建结构变量a
    a.size = init_size;
    a.array = (int*)malloc(sizeof(int)*a.size);
    //初始化大小和指针
    return a;
//返回a本身而不是指针,此时制作的是本地变量,因此可以在main函数中灵活使用
}

void array_free(Array *a)//上个函数中的结构里的*array需要释放
{
    free(a->array);
//为了保险起见,防止free两次(freeNULL是无害的),把这两个也初始化为0
    a->array = NULL;
    a->size = 0;
}

//既然只是想获得size,为什么不干脆printf里return a.size?还写函数干什么
//实际上,我们用函数将内部的实现细节封装起来,防止在大体量程序里直接调用带来的问题
//因为可能根本无法调用
int array_size(const Array *a)
{
    return a->size;
}

//为什么返回指针?因为这样做可以同时做到对指针的读和写
eg:*array_at(&a,0) = 10;//写入
    printf("%d\n",*array_at(&a,0));//读取
当然,写两个分开的函数也是可以的

int* array_at(Array *a, int index)
{
    return a->array[index];
    这样对吗?并不,注意这个函数的返回类型是个int指针,我们这样写返回的是int
    return &(a->array[index]);
}
//我们动态分配的内存空间实际上是不能长大的,是固定的
//所以思路是:重新分配一块空间,把原来空间上的东西复制到新的大空间
void array_inflate(Array *a,int more_size)
{
    int *p = (int*)malloc(sizeof(int)*(a->size + more_size));
    int i;
    for(i=0;i<a->size;i++){
        p[i] = a->array[i];
    }
//这个循环可以用库函数里的memcpy代替,理论效率更高
    free(a->array);
    a->array = p;
    a->size += more_size;
}

array.c main

int main()
{
    Array a = array_create(100);//创建结构a,数组大小为100
    printf("%d\n",array_size(&a));//打印数组大小
    *array_at(&a,0) = 10;//设置a[0]=10
    printf("%d\n",*array_at(&a,0));//打印a[0]

    int number = 0;
    int cnt = 0;
    //设置输入-1为退出条件
    while(number != -1){
        scanf("%d",&number);
        if(number != -1){
            *array_at(&a,cnt++) = number;
        }
    }
    array_free(&a);
    
    return 0;
}

此时可以实现不断输入数值填满数组,但是当数组越界时,还需要对程序进行一些修改

int* array_at(Array *a, int index)
{
    if(index >= a->size){
        array_inflate(a, index - a->size + 1);
      //因为每次读入一个数,所以就让数组上标增长1,
      //然而每次增长1都要重新申请,然后完整复制之前的数据,
      //因此我们定一个单位,每次越界都增长一个单位的大小,这样更加高效

        array_inflate(a, (index/BLOCK_SIZE + 1)*BLOCK_SIZE - a->size);
    //比如我要访问102,block大小为20,现在只有100,也就是5个block,
    //那么102/20=5,5+1=6,6*20=120,120-100=20,于是函数知道要增长20
    //如果越界更多,用这个公式也可以一次性算好
    }
    return &(a->array[index]);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值