一、IO
(一)文件分类
文本文件:存储ASCII码(0~127),以EOF作为结束符,一般存储数据量比较大的信息。
二进制文件:是数据在内存上的原样存储,存储的是二进制形式,一般存储中间变量,数据量比较小的信息,读取的速度快。
(二)按操作方式来分
(三)系统调用和库函数
(四)文件流指针和文件描述符
文件描述符:是一个正整数,其含义为fd_array数组下标
(五)IO分类
标准IO,文件IO
区别:
1、标准IO
(1)缓冲区的方式
全缓冲:缓冲区满了才刷新缓冲区,或者强制刷新缓冲区
行缓冲:碰到换行符刷新缓冲区、缓冲区满了刷新、或者强制刷新缓冲区
不缓冲:所有的信息到缓冲区之后直接到文件
(2)对文件进行操作
打开文件:fopen
操作文件:
以字符读写:fgetc 和 fputc
以行读写:fgets 和 fputs
以对对象读写:fread 和 fwrite
以格式化读写:fprintf 和 fscanf
关闭文件:fclose
标准IO相关的函数:
强制刷新:fflsh
判断文件是否到末尾:feof
时间函数:time localtime
光标移动:fseek
获取光标位置:ftell
2、文件IO
打开文件:open
操作文件:
读:read
写:write
关闭文件:close
对目录文件的操作:
打开目录:opendir
操作目录:readdir
获取指定文件的全部信息:stact
关闭目录:closedir
二、动态库、静态库
三、数据结构
(一)
(一)顺序表(线性结构的顺序存储)()
1、顺序表的定义
typedef int data_type; //把int命名成data_type
//定义顺序表
typedef struct list
{
/* member */
data_type *data; //用来指示表的存储空间
int size; //用来表示表的空间大小
int count; //用来指示表中元素的个数
}List;
2、顺序表的建立
//函数功能:创建顺序表
//函数参数:申请空间的个数
//函数返回值:成功返回创建的空间的首地址,失败返回NULL
List *CreateList(int my_size)
{
List *pList = NULL;//初始化
//申请表的空间
if(!(pList = (List *)malloc(sizeof(List))))
{
perror("error");
return NULL;
}
//给空间置空
memset(pList, 0, sizeof(List));
//申请存储空间
pList->data = (data_type *)malloc(my_size * sizeof(data_type));
if(!pList->data)
{
perror("List memary error");
return NULL;
}
memset(pList->data, 0, my_size * sizeof(data_type));
pList->size = my_size;
return pList;
}
3、顺序表的插入
//函数功能:插入元素
//函数参数1:待插入元素的顺序表
//函数参数2:要插入的位置
//函数参数3:要插入的值
//函数返回值:成功返回OK,失败返回失败原因
int InsertItem(List *pList, int pos, data_type item)
{
//入参判断
if(!pList) return LIST_NULL;
//判断表能否被插入
if(pList->count == pList->size) return LIST_FULL;
//检查pos有五问题
if(pos < -1 || pos >= pList->size) return POS_ERR;
if(pos == -1)
{
//尾插
//1。插入
pList->data[pList->count] = item;
pList->count++;
return OK;
}
//插入
//1.移动元素,为待插入元素预留位置
for(int i=pList->count; i>pos; i--)
{
pList->data[i] = pList->data[i-1];
}
//2。插入元素
pList->data[pos] = item;
//3。插入成功,成员数目发生变化 +1
pList->count++;
return OK;
}
4、顺序表的删除
//函数功能:删除元素
//函数参数1:给谁删除
//函数参数2:删除的位置
//函数参数3:删除的元素保存
//函数返回值:成功返回OK。失败返回失败原因
int DeleteItem(List *pList, int pos, data_type *item)
{
//入参判断
if(!pList) return LIST_NULL;
//判断链表是否为空
if(pList->count == 0) return LIST_EMPTY;
//判断POS是否有误
if(pos < 0 || pos >= pList->count) return POS_ERR;
//删除
//1。保存元素
*item = pList->data[pos];
//2。移动位置删除
for(int i=pos; i<pList->count-1; i++)
{
pList->data[i] = pList->data[i+1];
}
//3。count--
pList->count--;
return OK;
}
5、顺序表的显示
印顺序表
//从 data[0] ---> data[count-1]
for(int i=0; i<pList->count; i++)
{
printf("%d ", pList->data[i]);
}
puts(" ");
return OK;
}
6、顺序表的销毁
//函数功能:销毁顺序表
//函数参数:需要销毁的顺序表
//函数返回值:成功返回OK,失败返回失败原因
int Destory(List **pList)
{
printf("D before:%p\n", *pList);
//入参判断
if(!*pList) return LIST_NULL;
//销毁顺序表
//1。存储空间
free((*pList)->data);
//2.销毁顺序表本表
free(*pList);
//3。NULL
*pList = NULL;
printf("D after:%p\n", *pList);
return OK;
}
(二)带头结点的不循环单链表
1、结点定义
typedef int data_type; //把int命名成data_type
//定义单链表表结点
typedef struct link
{
/* member */
data_type Data;
struct link *Next;
}LNode;
2、创建链表
LNode *Create(void)
{
//定义变量
LNode *pLink = NULL;
//开辟空间
pLink = (LNode *)malloc(sizeof(LNode));
//判断是否成功
if(!pLink) return NULL;
//清空
memset(pLink, 0, sizeof(LNode));
//返回
return pLink;
}
3、插入结点
//函数功能:插入元素
//函数参数1:要插入元素的链表
//函数参数2:要插入的位置
//函数参数3:要插入的值
//函数返回值:成功返回OK,失败返回失败原因
int InsertItem(LNode *pHead, int pos, data_type item)
{
LNode *pNew = NULL;//定义指向新结点的变量
LNode *pTmp = pHead; //用来表示要插入位置的
int i = 0; //表示移动的次数
//入参判断
if(!pHead) return LINK_NULL;
//判断pos
if(pos < -1) return POS_ERR;
//创建结点
pNew = Create();
//给结点赋值
pNew->Data = item;
//插入
if(-1 == pos)
{
//尾插
//1.找到为结点
while(pTmp->Next != NULL)
{
//万后找
pTmp = pTmp->Next;
}
//插入:
pTmp->Next = pNew;
return OK;
}
//中间插入
//先找到要插入的位置:
while(i < pos && pTmp != NULL)
{
//往后移动
pTmp = pTmp->Next;
//次数++
i++;
}
if(pTmp == NULL) return POS_ERR;
//插入元素
//1。保护后面所有结点
pNew->Next = pTmp->Next;
//2。插入元素
pTmp->Next = pNew;
//3。返回OK
return OK;
}
4、显示链表
int ShowLink(LNode *pHead)
{
LNode *pTmp = NULL;
//入参盘算
if(!pHead) return LINK_NULL;
pTmp = pHead->Next;
//2.打印, 从 首 打印到 为结点
while(pTmp != NULL)
{
printf("%d ", pTmp->Data);
//往后移动
pTmp = pTmp->Next;
}
puts(" ");
return OK;
}
5、删除元素
//函数功能:删除元素
//函数参数1:待删除元素的链表
//函数参数2:待删除的位置
//函数参数3:删除的值
//函数返回值:成功返回OK,失败返回失败原因
int DeleteItem(LNode *pHead, int pos, data_type *item)
{
//定义变量,指向待删除的空间
LNode *pDel = NULL;
//指向操作删除的结点
LNode *pDel_Pre = NULL;
//定义表示移动次数的变量
int i = 0;
//入参判断
if(!pHead) return LINK_NULL;
//表为空
if(!pHead->Next) return LINK_EMPTY;
//pos错误:
if(pos < -1) return POS_ERR;
//初始值
pDel = pHead->Next;
pDel_Pre = pHead;
//根据pos取先则删除的位置
switch(pos)
{
case -1:
//尾删
//1.找到为结点
while(pDel->Next != NULL)
{
//往后移动
pDel = pDel->Next;
pDel_Pre = pDel_Pre->Next;
}
//2.保存元素
*item = pDel->Data;
//3.删除结点
pDel_Pre->Next = pDel->Next;
break;
case 0:
//头删
//1。保存元素
*item = pDel->Data;
//2.删除元素
pDel_Pre->Next = pDel->Next;
break;
default:
//中间删除
//1.找到要删除的结点
while(i < pos && pDel != NULL)
{
//往后移动
pDel = pDel->Next;
pDel_Pre = pDel_Pre->Next;
//次数++
i++;
}
if(pDel == NULL) return POS_ERR;
//2.保存元素
*item = pDel->Data;
//3.删除元素
pDel_Pre->Next = pDel->Next;
break;
}
//释放空间
free(pDel);
return OK;
}
(三)双链表(带头结点的不循环双链表)
1、结点定义
typedef int data_type; //把int命名成data_type
//定义双链表表结点
typedef struct doublelinknode
{
/* member */
struct doublelinknode *Pre;
data_type Data;
struct doublelinknode *Next;
}DbLNode;
2、创建
DbLNode *Create(void)
{
//定义变量
DbLNode *pLink = NULL;
//开辟空间
pLink = (DbLNode *)malloc(sizeof(DbLNode));
//判断是否成功
if(!pLink) return NULL;
//清空
memset(pLink, 0, sizeof(DbLNode));
//返回
return pLink;
}
3、插入
//函数功能:给双链表插入元素
//函数参数1:待插入元素的双链表
//函数参数2:要插入的位置
//函数参数3:要插入的值
//函数返回值:成功返回OK,失败返回失败原因
int InsertItem(DbLNode *pHead, int pos, data_type item)
{
DbLNode *pNew = NULL;
DbLNode *pTmp = pHead;
int i = 0;
//入参判断
if(!pHead) return DBLINK_NULL;
//poserr
if(pos < -1) return POS_ERR;
//创建空间
pNew = Create();
//赋值
pNew->Data = item;
//插入
//1.找到要插入的位置
while(i<pos && pTmp != NULL)
{
//往后移动
pTmp = pTmp->Next;
i++;
}
if(NULL == pTmp) return POS_ERR;
//插入
pNew->Pre = pTmp;
pNew->Next = pTmp->Next;
if(NULL != pTmp->Next)
{
pTmp->Next->Pre = pNew;
}
pTmp->Next = pNew;
return OK;
}
4、删除
//函数功能:删除元素
//函数参数1:待删除元素的链表
//函数参数2:删除的位置
//函数参数3:保存删除的值
//函数返回值:成功返回OK。失败返回失败原因
int DeleteItem(DbLNode *pHead, int pos, data_type *item)
{
int i = 0;
DbLNode *pDel = NULL; //定义变量
DbLNode *pDel_Pre = pHead ; //初始化
//入参判断
if(!pHead) return DBLINK_NULL;
//能否被删除元素
if(NULL == pHead->Next) return DBLINK_EMPTY;
//判断能否执行
if(pos < 0) return POS_ERR;
//删除元素
pDel = pHead->Next;
//1。找到要删除的元素
while(i<pos && pDel!=NULL)
{
//往后移动
pDel = pDel->Next;
pDel_Pre = pDel_Pre->Next;
//自家
i++;
}
if(pDel == NULL) return POS_ERR;
//2.保存元素
*item = pDel->Data;
//3.删除
if(pDel->Next != NULL)
{
pDel->Next->Pre = pDel_Pre;
}
pDel_Pre->Next = pDel->Next;
//4。释放空间
free(pDel);
return OK;
}
5、显示
int ShowList(DbLNode *pHead)
{
DbLNode *pTmp = NULL;
//入参判断
if(!pHead) return DBLINK_NULL;
pTmp = pHead->Next;//指向首届殿
//从首届殿打印到为结点
while(pTmp != NULL)
{
printf("%d ", pTmp->Data);
pTmp = pTmp->Next;
}
printf("\n");
return OK;
}
(四)受限的线性表栈(受限在了操作上)
1、栈的定义
//定义数据类型
typedef int data_type;
//栈的定义
typedef struct stack
{
data_type data[SIZE]; //存储空间
//只能在栈顶进行操作
int top; //指示栈顶
}Stack;
2、栈的创建
//函数功能:创建栈
//函数参数:void
//函数返回值:成功返回创建的首地址,失败返回NULL
Stack* CreateStack(void)
{
//定义变量
Stack *pStack = NULL; //初始化
//申请空间
if(NULL == (pStack = (Stack *)malloc(sizeof(Stack))))
{
perror("MALLOC_ERR");
return NULL;
}
//清空
memset(pStack, 0, sizeof(Stack));
//返回
return pStack;
}
3、入栈
//函数功能:入栈
//函数参数1:给谁入
//函数参数2:要赋值的值
//函数返回值:成功返回OK,失败返回失败原因
int Push(Stack *pStack, data_type item)
{
//入参判断
if(!pStack) return STACK_NULL;
//判断是否能入栈(栈是否满)
if(SIZE == pStack->top) return STACK_FULL;
//入栈
//先赋值,栈顶向上移动
pStack->data[pStack->top] = item;
pStack->top++;
return OK;
}
4、出栈
//函数功能:出栈
//函数参数1:给谁出
//函数参数2:出的谁
//函数返回值:成功返回OK,失败返回失败原因
int Pop(Stack *pStack, data_type *item)
{
//入参判断
if(!pStack) return STACK_NULL;
//判断是否能出栈(栈是否空)
if(0 == pStack->top) return STACK_EMPTY;
//出栈
//先向下移动,再赋值
pStack->top--;
*item = pStack->data[pStack->top];
return OK;
}
5、打印栈
//函数功能:显示栈
//函数参数:需要显示的栈
//函数返回值:成功返回OK,失败返回失败原因
int ShowItem(Stack *pStack)
{
if(!pStack) return STACK_NULL;
if(0 == pStack->top) return STACK_EMPTY;
//从i=0打印到i=top-1
for(int i = 0; i < pStack->top; i++)
{
printf("%d ", pStack->data[i]);
}
printf("\n");
return OK;
}
(五)队列(受限在了操作上 )
循环队列(解决普通队列的一次性问题)
//定义数据类型
typedef int data_type;
//队列的定义
typedef struct queue
{
data_type data[SIZE]; //存储空间
//在队尾插入、队头删除
int tail; //指示队尾
int head; //指示队头
}Queue;
//函数功能:创建顺序队列
Queue *Create(void)
{
Queue *pQueue = NULL;
pQueue = (Queue *)malloc(sizeof(Queue));
if(!pQueue) return NULL;
memset(pQueue, 0, sizeof(Queue));
return pQueue;
}
//函数功能:插入元素
//函数参数:待插入元素的队列
//函数参数:需要插入的元素
//函数返回值:成功返回OK,失败返回失败原因
int InsertItem(Queue *pQueue, data_type item)
{
//1.判断队列是否为NULL
if(!pQueue) return QUEUE_NULL;
//2.判断队列是否为满
if((pQueue->tail+1)%SIZE == (pQueue->head)%SIZE) return QUEUE_FULL;
//3.入队
pQueue->Data[pQueue->tail] = item;
//3。1赋值
pQueue->tail = (pQueue->tail + 1)%SIZE;
//3。2自加
return OK;
}
//函数功能:删除元素
//函数参数:待删除元素的队列
//函数参数:删除的元素
//函数返回值:成功返回OK,失败返回失败原因
int DeleteItem(Queue *pQueue, data_type *item)
{
//1.判断队列是否为NULL
if(!pQueue) return QUEUE_NULL;
//2.判断队列是否为空
if(pQueue->tail == pQueue->head) return QUEUE_EMPTY;
//3.出队
//3。1赋值
*item = pQueue->Data[pQueue->head];
//3。2自加
pQueue->head = (pQueue->head + 1)%SIZE;
return OK;
}
5、显示队列
//函数功能:显示队列
//函数参数:需要显示的队列
//函数返回值:成功返回OK,失败返回失败原因
int ShowQueue(Queue *pQueue)
{
//判断队列是否为NULL
if(!pQueue) return QUEUE_NULL;
//判断队列是否为空
if(pQueue->tail == pQueue->head) return QUEUE_EMPTY;
//打印
for(int i=0;i<SIZE;i++)
{
//队没有满打印完了退出,不继续
if((pQueue->head+i)%SIZE == pQueue->tail ) break;
printf("%d ",pQueue->Data[(pQueue->head+i)%SIZE]);
}
printf("\n");
return OK;
}
(六)什么时候考虑用栈?
入的顺序和出的顺序发生变化
栈的应用
四、树
(一)什么是树?
(二)二叉树
1、树的顺序存储

2、树形结构的链式存储:
(1)树结点的定义
typedef int data_type;
//定义链表结点数据类型
typedef struct bintreenode
{
/* member */
struct bintreenode *Left;
data_type Data;
struct bintreenode *Right;
}BTree;
(2)树结点的创建
//函数功能:申请空间
BTree *Creat(void)
{
//定义变量
BTree *pTree = NULL;
//申请空间
pTree = (BTree *)malloc(sizeof(BTree));
if(!pTree) return NULL;
//清空空间
memset(pTree, 0, sizeof(BTree));
//成功返回
return pTree;
}
(3)树结点的插入
int InsertItem(BTree *pTree, data_type item, int *Flag)
{
BTree *pNew = NULL; //指示新申请的空间
BTree *pTmp = pTree; //指示插入位置
//入参判断
if(!pTree) return TREE_NULL;
//判断是否为首次插入
if(*Flag)
{
//直接将要插入的值,赋值给Data域
pTree->Data = item;
//把标志位置空
*Flag = 0;
return OK;
}
//其余次 插入
//1。申请空间
pNew = Creat();
//2。赋值给
pNew->Data = item;
//3。找到要插入的位置
while(1)
{
if(item <= pTmp->Data)
{
//在左边
if( NULL == pTmp->Left)
{
//找到了,插入
pTmp->Left = pNew;
return OK;
}
//往左子树跑
pTmp = pTmp->Left;
}
else
{
//在右边
if( NULL == pTmp->Right)
{
//插入
pTmp->Right = pNew;
return OK;
}
//往右跑
pTmp = pTmp->Right;
}
}
}
(4)树结点的遍历
void Fri_Travel(BTree *pTree)
{
//退出条件
if(NULL == pTree) return ;
//先访问根结点
printf("%d ", pTree->Data);
//以先序便利的形式,访问左子树
Fri_Travel(pTree->Left);
//以先序便利的形式,遍历右子树
Fri_Travel(pTree->Right);
}
void Mid_Travel(BTree *pTree)
{
//退出条件
if(NULL == pTree) return ;
//先遍历左子树
Mid_Travel(pTree->Left);
printf("%d ", pTree->Data);
Mid_Travel(pTree->Right);
}
void Fin_Travel(BTree *pTree)
{
if(NULL == pTree) return;
Fin_Travel(pTree->Left);
Fin_Travel(pTree->Right);
printf("%d ", pTree->Data);
}
五、网状结构
有向图:十字链表法
六、算法
(一)算法的特征:
(二)怎么样评判算法的好坏:
(三)常见的查找算法
(四)常见的排序算法
1、内部排序
(插入)
直接插入:重新构建一个链表
折半插入:和二分查找类似
(交换)
冒泡
每一次运行总会将最小的或者最大的放到前面,如果需要交换,一直在交换

(选择)
(基数排序)