查找算法
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;
}

348

被折叠的 条评论
为什么被折叠?



