1. 一个函数想要给函数的调用者传递值 有__地址传递__和_返回值___两种方式。
2. 如何避免头文件重复包含?
#ifndef
#define
#endif
3. 顺序表和链表的相同点和不同点有哪些?
相同点: 线性逻辑结构,一对一
不同点:(1)顺序存储在内存当中你分配连续一片空间;链式存储不连续
- 顺序表(数组)长度固定,链表不固定
- 顺序表查找方便,插入删除麻烦;链表查找麻烦,插入删除方便
4. 线性表的特征是什么?
线性表: 顺序表链表(顺序栈和链式栈)队列(顺序队列也叫循环队列,链式队列)
线性表的特征:一对一,每个节点最多有一个前去和一个后继(首尾节点除外)
///
1 队列(queue)
顺序队列(循环队列) 和 链式队列
1.1 什么是队列?
只允许在两端进行插入和删除操作的线性表,在队尾插入,在队头删除 插入的一端,被称为"队尾",删除的一端被称为"队头"
在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组作为循环队列的操作空间。
1.2 队列的特点
先进先出 FIFO first in first out
后进后出 LILO last
1.3 举例:
去银行办理业务,需要排队,有个先来后到,先来的先办业务
循环队列
1.4循环队列的思想
循环队列中,假设数组的元素个数为N,那么循环队列中存储最多的数据个数为N-1个
原因:思想上,舍去数组上的一个存储位置,用于判断队列是否为满,先判断rear的下一个位置是否等于front
return (p->rear+1) % N == p->front;
2. 顺序队列(又称为循环队列)
逻辑结构: 线性结构
存储结构:顺序存储结构
循环队列,如果数组的元素个数为N,那么队列中最多能够存储的数据数的多少? N-1个
为什么?
rear 后面 队尾,在插入的时候,插入之前需要先判断 rear+1,
也就是他的下一个为位置是否 等于 front 来判断队列是否为满,会造成浪费一个存储位置
流程概述:
#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef int datatype;
typedef struct
{
datatype data[N];//循环队列的数组
int rear;//存数据端 rear 后面
int front;//取数据端 front 前面
}sequeue_t;
//1.创建一个空的队列
sequeue_t *CreateEmptySequeue();
//2.入列 data代表入列的数据
int InSequeue(sequeue_t *p,datatype data);
//3.判断队列是否为满
int IsFullSequeue(sequeue_t *p);
//4.判断队列是否为空
int IsEmptySequeue(sequeue_t *p);
//5.出列
datatype OutSequeue(sequeue_t *p);
//6.求队列的长度
int LengthSequeue(sequeue_t *p);
//7.清空队列函数
void ClearSequeue(sequeue_t *p);
流程实现:
#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef int datatype;
typedef struct
{
datatype data[N];//循环队列的数组
int rear;//存数据端 rear 后面
int front;//取数据端 front 前面
}sequeue_t;
//1.创建一个空的队列
sequeue_t *CreateEmptySequeue();
//2.入列 data代表入列的数据
int InSequeue(sequeue_t *p,datatype data);
//3.判断队列是否为满
int IsFullSequeue(sequeue_t *p);
//4.判断队列是否为空
int IsEmptySequeue(sequeue_t *p);
//5.出列
datatype OutSequeue(sequeue_t *p);
//6.求队列的长度
int LengthSequeue(sequeue_t *p);
//7.清空队列函数
void ClearSequeue(sequeue_t *p);
int main(){
int i;
sequeue_t* p = NULL;
p = CreateEmptySequeue();
for (i = 0; i < N-1; i++)
{
InSequeue(p, i);//入队0 1 2 3 4,4会失败,因为多了一位,留了一个位置没有存数据
}
printf("len is %d\n", LengthSequeue(p));//4
printf("rear is %d,front is %d\n", p->rear, p->front);//4 0
OutSequeue(p);//front --> 1 rear ---> 4
printf("rear is %d,front is %d\n", p->rear, p->front);//4 1
OutSequeue(p);//front --> 2 rear ---> 4
printf("rear is %d,front is %d\n", p->rear, p->front);//4 2
InSequeue(p, 100);// front --->2 rear ---> 0,满足rear < front
printf("rear is %d front is %d\n", p->rear, p->front);//0 2
printf("len is %d\n", LengthSequeue(p));
while (!IsEmptySequeue(p))
{
printf("%d ", OutSequeue(p));
}
printf("\n");
free(p);
p = NULL;
// system("pause");
return 0;
}
//1.创建一个空的队列
sequeue_t* CreateEmptySequeue()
{
sequeue_t* p = (sequeue_t*)malloc(sizeof(sequeue_t));
if (p == NULL) {
printf("error\n");
return NULL;
}
p->rear = 0;
p->front = 0;
return p;
}
//3.判断队列是否为满
int IsFullSequeue(sequeue_t* p)
{
return (p->rear + 1) % N == p->front;
}
//4.判断队列是否为空
int IsEmptySequeue(sequeue_t *p)
{
return p->front==p->rear;
}
//2.入列 data代表入列的数据
int InSequeue(sequeue_t* p, datatype data)
{
//1.容错判断
if (IsFullSequeue(p)) {
return -1;
}
//2.入列,从rear移动
p->data[p->rear] = data;//插入数据
p->rear = (p->rear + 1) % N;//尾往后移
return 0;
}
//5.出列
datatype OutSequeue(sequeue_t *p){
if (IsEmptySequeue(p)) {
return -1;
}
datatype temp;
temp= p->data[p->front];
p->front=(p->front+1)%N;
if (IsEmptySequeue(p)) {
return -1;
}
return temp;
}
//6.求队列的长度
int LengthSequeue(sequeue_t *p)
{
return (p->rear-p->front+N)%N;
/*
if (p->rear >= p->front) {//尾巴大于等于头
return p->rear - p->front;
}
else {//头大于尾巴
return p->rear - p->front + N;
}
*/
}
//7.清空队列函数
void ClearSequeue(sequeue_t *p)
{
while(!IsEmptySequeue(p)) {
OutSequeue(p);
}
}
链式队列
逻辑结构: 线性结构
存储结构:链式存储
/链式队列操作//
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
datatype data;//数据域
struct node *next;//指针域
}linkqueue_node_t,*linkqueue_list_t;
//linkqueue_list_t p === linkqueue_node_t *
typedef struct//将队列头指针和尾指针封装到一个结构体里
{
linkqueue_list_t front;//相当于队列的头指针
linkqueue_list_t rear;//相当于队列的尾指针
//有了链表的头指针和尾指针,那么我们就可以操作这个链表
}linkqueue_t;
//1.创建一个空的队列
linkqueue_t *CreateEmptyLinkQueue();
//2.入列 data代表入列的数据
int InLinkQueue(linkqueue_t *p,datatype data);
//3.出列
datatype OutLinkQueue(linkqueue_t *p);
//4.判断队列是否为空
int IsEmptyLinkQueue(linkqueue_t *p);
//5.求队列长度的函数
int LengthLinkQueue(linkqueue_t *p);
//6.清空队列
void ClearLinkQueue(linkqueue_t *p);
流程实现
#include<stdio.h>
#include<stdlib.h>
typedef int datatype;
typedef struct node_t
{
datatype data;//数据域
struct node_t* next;//指针域
}linkqueue_node_t, * linkqueue_list_t;
typedef struct
{
linkqueue_list_t front;//指向链表的头节点
linkqueue_list_t rear;//指向链表的尾节点
}linkqueue_t;
//1.创建一个空的队列
linkqueue_t* createEmptyLinkQueue();
//2.入列 data代表入列的数据
int inLinkQueue(linkqueue_t* p, datatype data);
//4.判断队列是否为空
int isEmptyLinkQueue(linkqueue_t* p);
//3.出列
datatype outLinkQueue(linkqueue_t* p);
//5.求队列长度的函数
int lengthLinkQueue(linkqueue_t* p);
//6.清空队列
void clearLinkQueue(linkqueue_t* p);
int main(){
int i;
datatype data;//用于保存出列的数据
linkqueue_t *p = createEmptyLinkQueue();
for(i = 1; i < 6; i++)
{
inLinkQueue(p,i);//入列的顺序是 1 2 3 4 5
}
printf("len is %d\n",lengthLinkQueue(p));
while(!isEmptyLinkQueue(p))//出列打印的顺序为 1 2 3 4 5 因为先进先出 队列的特点
{
data = outLinkQueue(p);
printf("%d ",data);
}
printf("\n");
free(p->front);
p->front = NULL;
p->rear = NULL;
free(p);
p=NULL;
return 0;
}
//1.创建一个空的队列
linkqueue_t* createEmptyLinkQueue()
{
//申请空间存放队列的结构体
linkqueue_t* p = (linkqueue_t*)malloc(sizeof(linkqueue_t));
if (p == NULL)
{
perror("createEmptyLinkQueue");
return NULL;
}
//给队列的结构体进行初始化(头尾指针分别指向开辟头节点)
p->front = p->rear = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
if (p->front == NULL)
{
perror("p->front malloc err");
return NULL;
}
//头节点初始化
p->front->next = NULL;
return p;
}
//2.入列 data代表入列的数据
int inLinkQueue(linkqueue_t* p, datatype data)
{
//1.创建一个新的节点,用来保存即将插入的数据
linkqueue_list_t pnew = (linkqueue_list_t)malloc(sizeof(linkqueue_node_t));
if (NULL == pnew)
{
perror("inLinkQueue pnew malloc failed");
return -1;
}
//2.将入列的数据放入到新的节点中
pnew->data = data;
pnew->next = NULL;
//3.将新节点链链接到链表的尾巴
p->rear->next = pnew;//新节点链接到链表的尾
p->rear = pnew;//rear移动,因为rear永远指向当前链表的尾
return 0;
}
//4.判断队列是否为空
int isEmptyLinkQueue(linkqueue_t* p)
{
return p->rear == p->front;
}
//3.出列
datatype outLinkQueue(linkqueue_t* p)
{
linkqueue_list_t pdel = NULL;//指向被删除的节点
//1.容错判断
if (isEmptyLinkQueue(p))
{
perror("isEmptyLinkQueue!!\n");
return -1;
}
//2.数据出列
//(1)定义pdel指向即将被删除的节点就是front指向的节点,
//出列每次删除的都是front指向的那个节点
pdel = p->front;
//(2)将front向后移动一个位置
p->front = p->front->next;
//(3)释放被删除节点
free(pdel);
pdel = NULL;
//(4)将数据出列
return p->front->data;
}
//5.求队列长度的函数
int lengthLinkQueue(linkqueue_t* p)
{
int len = 0;
linkqueue_list_t h = p->front;
while (h->next != NULL) {
h = h->next;
len++;
}
return len;
}
//6.清空队列
void clearLinkQueue(linkqueue_t* p)
{
if (!isEmptyLinkQueue(p)) {
outLinkQueue(p);
}
}