day 25 数据结构 查找及IO

查找算法

1.顺序查找

关键字:分主关键字和此关键字。

主关键字:可以识别一条记录,身份证号,学号等

次关键字:可以识别若干记录、性别、年龄等

顺序查找概念:按照顺序逐一比较,查找某个关键字,是否存在线性表

#include <myhead.h>
#define MAX 100
typedef struct
{
    char name[20];
    char sex[5];
    int age;
}student;//学生信息结构体
typedef  struct
{
    int len;
    student data[MAX];
}list,*Plist;//顺序表结构体
int main(int argc, const char *argv[])
{
    char name[20];
    int i,flag = 0;
    list s = {5,{{"小胖","男",21},{"细狗","男",22},{"黑狗","女",21},{"添狗","男",19},{"狼狗","女",22}}};
#if 0
    //查找存在或者不存在的情况
    printf("请输入姓名关键字:");
    scanf("%s",name);
    for(i = 0;i<s.len;i++)
    {
        if(strcmp(name,s.data[i].name)==0)
        {
            printf("查找成功该学生是:%s,年龄:%d\n",s.data[i].name,s.data[i].age);
            flag = 1;//查找成功改变flag 的值
        }
    }
    if(flag==0)
    {
        printf("查找失败\n");
    }
#endif
    //查找多个相同关键字,要求输出最后一个或者第一个。
    int age,sub = -1;
    printf("请输入年龄关键字:");
    scanf("%d",&age);
    for(i = 0;i<s.len;i++)
    {
        if(age==s.data[i].age)
        {
            sub = i;//保留下标
            //break;查找第一个加上break
        }
    }
    if(sub==-1)
    {
        printf("查找失败\n");
    }
    else
    {
        printf("查找成功该学生是:%s,年龄:%d\n",s.data[sub].name,s.data[sub].age);
    }
    return 0;
}

2.折半查找(二分查找)

1.折半查找:前提是顺序存储,记录有序,每一次排除一般元素,直到区间范围内没有元素为止。

时间复杂度O(log2(n))

#include <myhead.h>
#define MAX 100
typedef struct
{
    char name[20];
    char sex[5];
    int age;
}student;//学生信息结构体
typedef  struct
{
    int len;
    student data[MAX];
}list,*Plist;//顺序表结构体
int main(int argc, const char *argv[])
{
    int age;
    int flag = 0;
    list s = {5,{{"小胖","男",30},{"细狗","男",28},{"黑狗","女",25},{"添狗","男",21},{"狼狗","女",19}}};
    printf("请输入查找的年龄:");
    scanf("%d",&age);
    int i=0,j = s.len-1,mid;
    while(i<=j)
    {
        mid = (i+j)/2;
        if(age>s.data[mid].age)//比中间值大往左找
        {
            j = mid-1;
        }
        else if(age<s.data[mid].age)//比中间值大往右找
        {
            i = mid+1;
        }
        else
        {
            printf("查找成功,该学生是:%s\n",s.data[mid].name);
            flag = 1;
            break;
        }
    }
    if(flag==0)
    {
        printf("查找失败\n");
    }
}

3.哈希查找

1、哈希表概念:利用哈希函数关键字代入哈希函数,算出下标,把关键字存入下标对应的数组中。

哈希表的构建:哈希函数,数组,解决冲突方法。

哈希函数构建方法:直接定址法,数字分析法,平方取中,除留余数

1、直接定址法:采用某个线性函数产生的地址作为下标。eg:f(x) =2*x+1

2、数字分析法:取数字的前两位或者后三位作为下标。

3、平方取中法:将关键字平方后取中间某几位作为下标。

4、除留余数法(常用):将关键字模某个值,产生的下标作为地址eg:f(x) = x%13;

解决冲突方法:线性探测再散列,二次探测再散列,再哈希(重新构建新的哈希函数)等。

1、冲突:不同关键字带入哈希函数得到相同下标。

2、线性探测再散列:逐一往后+1的方式探测。

3、二次探测再散列:逐一往后+i^2方式探测。

4、再哈希:重新构建新的哈希函数。

时间复杂度O(1)。

假设由关键字:{12,14,21,36,18,66,16}构建哈希表,哈希函数是H(key) = key%7

采用线性探测解决冲突,表中初始值为-1.请构建哈希表。

#include <myhead.h>

int main(int argc, const char *argv[])
{
    int i,sub;
    int hash[13];//哈希表长度13
    for(i = 0;i<13;i++)//将哈希表初始化为-1
    {
        hash[i] = -1;
    }
    int a[7] = {12,14,21,36,18,66,16};//关键字
    for(i = 0;i<7;i++)//7个元素
    {
        sub = a[i]%7;//将所有的关键字代入哈希函数算出下标
        while(hash[sub]!=-1)//产生了冲突
        {
            sub = (sub+1)%13;//(下标+1)%表长(线性探测)
        }
        hash[sub] = a[i];//将关键字放入哈希表
    }
    
    for(i = 0;i<13;i++)
    {
        printf("%d\t",hash[i]);
    }

    //哈希查找
    int key,count=0;
    printf("请输入要查找的关键字:");
    scanf("%d",&key);
    sub = key%7;//代入哈希函数算出下标
    while(hash[sub]!=key)//没有该关键字继续线性探测
    {
        sub = (sub+1)%13;
        count++;
        if(count%13==0)//查找一圈了
        {
            break;
        }
    }
    if(count==13)
    {
        printf("查找失败\n");
        return -1;
    }
    printf("查找成功,在第%d个位置\n",sub+1);
    return 0;
}

IO

学习方法:不要死记硬背,学会使用man手册查,加上有道翻译去理解。

input:输入,output:输出

IO是计算机中的输入/输出(Input/Output)的简称,指的是计算机系统与外部设备之间进行数据交换的过程。输入是指将外部数据传输到计算机系统中,输出是指将计算机系统中的数据传输到外部设备中。

标准IO,也称为高级IO,是C语言标准库提供的一种IO操作方式。它使用文件流指针(如stdin、stdout、stderr)作为操作入口,通过缓冲机制(全缓冲、行缓冲、不缓冲)来管理数据的输入和输出。标准IO提供了丰富的函数接口,如fopen、fclose、fread、fwrite等,方便开发者进行文件操作

文件IO,也称为低级IO,是Linux系统调用提供的一种IO操作方式。它通过文件描述符(0,1,2)来访问文件,文件描述符是一个非负整数,用于标识打开的文件。文件IO没有缓冲机制,直接对文件进行读写操作。常见的文件IO函数有open、close、read、write等。

1、标准IO依赖C标准库,使用时调用C标准库的函数,在写入或者读取数据时,标准IO先将数据放入缓冲区,当缓冲区满了或者刷新时机到了,标准IO会调用文件IO将数据写入硬件或者从硬件读取出来。

2、标准IO = 文件IO+缓冲区

3、标准IO函数:scanf/printf getchar/putchar gets/puts

4、文件IO依赖于系统调用,文件IO没有缓冲区,每一次调用,系统都会进行一次内核态到用户态的切换,也就是每一次调用系统都处于阻塞状态,等待用户程序执行完成,所以文件IO调用时非常浪费系统开销。

3、创建递归索引

1、进入 cd /usr/include    专门用来存放头文件的目录

2、sudo ctags -R      在存放头文件的目录里面,创建一个搜索列表

3、vim -t 想要查看的数据名    前两步是一次性操作,之后想要查看其他内容,直接执行第三步即可

标准IO封装的结构体内部有缓冲区。
struct _IO_FILE {


  char* _IO_buf_base;    /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
};

4、文件IO

依赖系统调用,由内核封装的一系列函数,可以直接作用于操作系统,每一次调用操作系统都处于阻塞状态,等待文件IO进程的完成,所以使用文件IO系统开销非常大。

5、标准IO缓冲区指针

stdin:标准输入流指针,调用标准IO输入函数时,标准IO输入函数操作的指针,将数据放入stdin指向的缓冲区。

stdout:标准输出流指针,调用标准IO输出函数时,标准IO输出函数操作的指针,将数据从stdout指向的缓冲区输出。

stderr:标准出错流指针,调用标准IO错误函数时,标准IO错误函数操作的指针,没有缓冲区,出错信息会立刻显示出来。

6、fopen/fclose

#include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);
       功能:打开文件
       参数1:指向文件的指针(一般写成路径)
           绝对路径:home/ubuntu/24101/IO/IO-1/1.txt 是从家目录出发的一整条完整的路径。
           相对路径:/1.txt 当前文件夹下的某个文件。
       参数2:打开模式由6种可选
           r:只读方式打开文件,光标位于文件的开头。
           r+:读写方式打开文件,光标位于文件的开头。
           w:只写方式打开文件,如果文件不存在就创建文件,如果文件存在就清空文件内容,
           光标位于文件的开头。
           w+:读写方式打开文件,如果文件不存在就创建文件,如果文件存在就清空文件内容,
           光标位于文件的开头。
           a:追加写的方式打开文件,如果文件不存在就创建文件,光标位于文件的末尾
           a+:读和追加写的方式打开文件,如果文件不存在就创建文件,读的时候光标位于文件的开
           头,写的时候光标位于文件的末尾。                                 
    返回值:成功返回指向打开的文件指针,失败返回NULL,并置位错误码。
    
     #include <stdio.h>

       int fclose(FILE *stream);
       功能:关闭文件指针指向的文件,将光标重置到文件开头。
       参数1:文件指针
       返回值:成功返回0,失败返回EOF(-1)并置位错误码。
#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp1,*fp2,*fp3,*fp4,*fp5,*fp6;
    if((fp1=fopen("./1.txt","r"))==NULL)//只读方式打开文件
    {
        perror("open");
    }
    if((fp2=fopen("/home/ubuntu/24101/IO/IO-1/1.txt","r+"))==NULL)//读写方式打开文件
    {
        perror("open");
    }

    if((fp3=fopen("./1.txt","w"))==NULL)//只写方式打开文件如果文件不存在就创建,如果存在就清空
    {
        perror("open");
    }
    if((fp4=fopen("./1.txt","w+"))==NULL)//读写方式打开文件如果文件不存在就创建,如果存在就清空
    {
        perror("open");
    }

    if((fp5=fopen("./1.txt","a"))==NULL)//追加写的方式打开文件,光标位于文件的末尾
    {
        perror("open");
    }
    if((fp6=fopen("./1.txt","r"))==NULL)//追加写和读的方式打开文件,读时光标位于文件开头,写时位于文件末尾
    {
        perror("open");
    }    

    fclose(fp1);
    fclose(fp2);
    fclose(fp3);
    fclose(fp4);
    fclose(fp5);
    fclose(fp6);
    return 0;
}
#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp = fopen("./xiaopang.txt","r+");
    if(fp==NULL)
    {
        printf("错误码:%d,错误信息:%s\n",errno,strerror(errno));
        perror("fopen");
    }    
    return 0;
}

fgetc fputc

 #include <stdio.h>

       int fgetc(FILE *stream);
    功能:从stream指向的文件中,读取一个单字符。
    参数:指向文件的指针
    返回值:成功返回读取的字符,读取到文件末尾或者失败返回EOF(-1)
    
     #include <stdio.h>

       int fputc(int c, FILE *stream);
       功能:将字符c写入到stream指向的文件中
       参数1:字符变量或者常量
       参数2:指向文件的指针
       返回值:成功返回写入的字符,失败返回EOF。
#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp = fopen("./1.txt","r");
    if(fp==NULL)
    {
        perror("fopen");
    }
    char ch;
#if 0
    ch = fgetc(fp);//从fp指向的文件中读取单字符
    printf("%c\n",ch);
    ch = fgetc(fp);//从fp指向的文件中读取单字符
    printf("%c\n",ch);
    ch = fgetc(fp);//从fp指向的文件中读取单字符
    printf("%c\n",ch);
#endif
    //循环读取文件单字符,读取到EOF结束
    while((ch = fgetc(fp))!=EOF)
    {
        printf("%c",ch);
    }

    fclose(fp);//关闭文件1

    ch = 'W';
    fp = fopen("./2.txt","w");//只写方式打开文件2
    if(fp==NULL)
    {
        perror("fopen");
    }
    fputc('A',fp);//写入常量
    fputc('B',fp);
    fputc('C',fp);
    fputc(ch,fp);//写入变量
    fclose(fp);//关闭文件指针
    return 0;
}

练习:循环读取1文件内容写入2文件

#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp1=fopen("./1.txt","r");
    FILE *fp2=fopen("./2.txt","w");
    char ch;
    while((ch=fgetc(fp1))!=EOF)
    {
        fputc(ch,fp2);
    }
    fclose(fp1);
    fclose(fp2);    
    return 0;
}

fgets fputs

#include <stdio.h>
       char *fgets(char *s, int size, FILE *stream);
       功能:从stream指向的文件中读取size-1个字符放入s指向的缓冲区,在末尾加上'\0'。
       读取时连同换行一起读取。
       参数1:字符串存储的起始地址。
       参数2:读取的大小size-1个字符
       参数3:文件指针。
       返回值:成功返回读取的字符串,失败或者读取到文件末尾返回NULL.
#include <stdio.h>

      
       int fputs(const char *s, FILE *stream);
       功能:将s指向的字符串写入到stream指向的文件
       参数1:字符串起始地址
       参数2:文件指针
       返回值:成功返回非负数,失败返回EOF(-1)。
#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp = fopen("./1.txt","r");
    char buff[1024];
    while(1)
    {
        char *s = fgets(buff,sizeof(buff),fp);
        if(s==NULL)//读取到文件末尾
        {
            break;
        }
        printf("%s",buff);//输出文件内容
    }
    fclose(fp);

    fp = fopen("./1.txt","w");//只写方式打开文件

    fputs("你说是不是",fp);//写入常量
    strcpy(buff,"唐明于是好人");
    fputs(buff,fp);//写入字符串
    fclose(fp);
    return 0;
}

练习:实现将文件1的内容复制到文件2

#include <myhead.h>

int main(int argc, const char *argv[])
{
    FILE *fp = fopen("./1.txt","r");
    FILE *fp2 = fopen("./2.txt","w+");
    if(fp==NULL||fp2==NULL)
    {
        perror("fopen");
        return -1;
    }
    char buff[1024];
    while(1)
    {
        char *s = fgets(buff,sizeof(buff),fp);//读取1文件内容返回值s指向buff
        if(s==NULL)
        {
            break;
        }
        fputs(buff,fp2);//写入到2文件
    }    
    return 0;
}

sprintf snprintf

 #include <stdio.h>

     
       int sprintf(char *str, const char *format, ...);
       功能:将变量常量按照格式转换字符的形式写入到字符串str中
       参数1:字符数组或者字符串
       参数2:格式控制字符串
       参数3,4,5,6...:要写入字符串的数据(变量或者常量)
        eg:
        sprintf(str,"%s %d %f","班长是好人",100,12.5);
        但是无法预知要写入的字符串长度,可能会导致str的溢出
       int snprintf(char *str, size_t size, const char *format, ...);
        功能:将变量常量按照格式转换字符的形式写入到字符串str中
        参数1:字符数组或者字符串
        参数2:要写入的字节个数
        参数3:格式控制字符串
        参数4,5,6...:要写入字符串的数据(变量或者常量)
       
#include <myhead.h>

int main(int argc, const char *argv[])
{
    char str[100];
    int a = 99;
    float b = 12.5;
    sprintf(str,"%s %d %f","明天放假那是不可能的",a,b);
    char buff[1024] = "qwertyu";
    sprintf(str,"%s %d %f",buff,a,b);
    printf("%s\n",str);


    snprintf(str,sizeof(str),"%s %d %f",buff,a,b);
    printf("%s\n",str);
    
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值