数据结构——栈、队列和数组(Code)

下面写的代码可能感觉会很乱,所以加上了目录,意在为了引导,也就是你需要回顾哪个算法,就能够快速定位到该位置,如果从上往下去找的话,估计脑壳也疼死了。

二、栈和队列的存储结构

(一)栈的顺序存储结构
  1. 结构体的声明
#define MAX_SIZE 30					//设置顺序表最大容量
typedef struct
{
	int data[MAXSIZE];				//存放栈中的元素,MAXSIZE为最大结点个数
	int top;						//top,栈顶指针
}SQ_STACK;
  1. 栈的初始化
/*
method:
	初始化一个栈
param:
	sq_stack 栈
*/
void Init_Stack(SQ_STACK* sq_stack)
{
	sq_stack->top = -1;				//栈内元素为空,栈顶指针设置为-1
}
  1. 判断栈是否为空
/*
method:
	判断栈是否为空
param:
	sq_stack	栈
*/
int Is_Stack_Empty(SQ_STACK* sq_stack)
{
	if (sq_stack->top == -1)		//栈顶指针为-1,即为空
		return OK;
	else
		return ERROR;
}
  1. 进栈操作
/*
method:
	进栈操作
param:
	sq_stack	栈
	data		要进栈的元素值
*/
int Push(SQ_STACK* sq_stack, int data)
{
	if (sq_stack->top == MAXSIZE - 1)			//判断是否栈满
		return ERROR;
	sq_stack->data[++sq_stack->top] = data;		//入栈,++sq_stack->top 这里 先将sq_stack->top自增,然后再存储
	return OK;
}

  1. 出栈操作
/*
method:
	出栈操作
param:
	sq_stack	栈
	data		出栈的元素值
*/
int	Pop(SQ_STACK* sq_stack,int *data)
{
	if (sq_stack->top == -1)						//判断是否栈空
		return ERROR;
	(*data) = sq_stack->data[sq_stack->top--];		//sq_stack->top-- 这里先取出来值,然后sq_stack->top再自减
	return OK;
}
(二)栈的链式存储结构
  1. 结构体的声明
typedef struct LSTACK
{
	int data;								//数据与
	struct LSTACK* next;					//指针域
}LSTACK;
  1. 栈的初始化
/*
method:
	初始化一个栈
param:
	lstack 栈
*/
void Init_LStack(LSTACK *lstack)
{
	lstack->next = NULL;										//将指针置位NULL
}
  1. 判断栈是否为空
/*
method:
	判断栈是否为空
param:
	lstack	栈
*/
int Is_LStack_Empty(LSTACK* lstack)
{
	if (lstack->next == NULL)									//判断是否栈空		
		return OK;
	else
		return ERROR;
}
  1. 进栈操作
/*
method:
	进栈操作
param:
	lstack	栈
	data		要进栈的元素值
*/
int L_Push(LSTACK* lstack, int data)
{
	LSTACK* q;
	q = (LSTACK*)__vcrt_malloc_normal(sizeof(LSTACK));			//为新结点创建内存空间
	q->data = data;												//新创建的结点存储数据
	q->next = lstack->next;										//入栈操作
	lstack->next = q;
	return OK;
}
  1. 出栈操作
/*
method:
	出栈操作
param:
	lstack		栈
	data		出栈的元素值
*/
int	L_Pop(LSTACK* lstack, int* data)
{
	LSTACK* p;
	if (lstack->next == NULL)									//判断是否栈空
		return ERROR;
	p = lstack->next;											//出栈操作
	*data = p->data;
	lstack->next = p->next;
	__vcrt_free_normal(p);										//释放内存
	return OK;
}
(三)队列的顺序存储结构
  1. 双链表结构体
#define MAXSIZE		20

typedef struct
{
	int data[MAXSIZE];				//存放到队列中的元素,MAXSIZE为最大结点个数
	int front;						//队头指针
	int rear;						//队尾指针
}SQ_QUEUE;
  1. 队列的初始化
/*
method:
	初始化一个队列
param:
	sq_queue 队
*/
void Init_Queue(SQ_QUEUE* sq_queue)
{
	sq_queue->front = sq_queue->rear = 0;				//队列内元素为空,队列首尾指针相同,设置为0
}
  1. 判断队列是否为空
/*
method:
	判断队列是否为空
param:
	sq_queue	队
*/
int Is_Queue_Empty(SQ_QUEUE* sq_queue)
{
	if (sq_queue->front == sq_queue->rear)				//队头指针指向队尾指针即为空
		return OK;
	else
		return ERROR;
}
  1. 进队操作
/*
method:
	进队操作
param:
	sq_queue	队
	data		要进队的元素值
*/
int En_Queue(SQ_QUEUE* sq_queue, int data)
{
	if ((sq_queue->rear + 1)%MAXSIZE == sq_queue->front)			//判断是否队列已满
		return ERROR;
	sq_queue->rear = (sq_queue->rear + 1) % MAXSIZE;				//为了循环插入到队列中
	sq_queue->data[sq_queue->rear] = data;							//入队
	return OK;
}
  1. 出队操作
/*
method:
	出队操作
param:
	sq_queue	栈
	data		出队的元素值
*/
int	De_Queue(SQ_QUEUE* sq_queue, int* data)
{
	if (sq_queue->front == sq_queue->rear)							//判断是否队列为空
		return ERROR;
	sq_queue->front = (sq_queue->front + 1) % MAXSIZE;				//为了构成循环队列
	*data = sq_queue->data[sq_queue->front];						//出队
	return OK;
}

(四)队列的链式存储结构
  1. 结构体的声明
typedef struct LNODE						//链式队列的结点的结构体
{		
	int data;								//用于存放数据元素
	struct LNODE* next;						//指向下一个结点
}LNODE;

typedef struct LQUEUE						//队头队尾结构体
{
	LNODE* front;							//队头指针
	LNODE* rear;							//队尾指针
}LQUEUE;
  1. 队列的初始化
/*
method:
	初始化一个队列
param:
	sq_queue 队
*/
void Init_LQueue(LQUEUE* lqueue)
{
	lqueue->front = lqueue->rear = NULL;				//队列内元素为空,队列首尾指针相同,设置为0
}
  1. 判断队列是否为空
/*
method:
	判断队列是否为空
param:
	lqueue	队
*/
int Is_LQueue_Empty(LQUEUE* lqueue)
{
	if (lqueue->front == NULL || lqueue->rear == NULL)		//判断是否队列为空
		return OK;
	else
		return ERROR;
}
  1. 进队操作
/*
method:
	进队操作
param:
	lqueue		队
	data		要进队的元素值
*/
int En_LQueue(LQUEUE* lqueue, int data)
{
	LNODE* p = (LNODE*)__vcrt_malloc_normal(sizeof(LNODE));	//分配内存
	p->data = data;											//获取进队元素
	p->next = NULL;
	if (lqueue->front == NULL || lqueue->rear == NULL)		//判断是否队列为空
	{
		lqueue->front = lqueue->rear = p;					//第一个元素,队头队尾都指向该结点
	}
	else
	{
		lqueue->rear->next= p;								//入队操作
		lqueue->rear = p;
	}
	return OK;
}
  1. 出队操作
/*
method:
	出队操作
param:
	lqueue		栈
	data		出队的元素值
*/
int	De_LQueue(LQUEUE* lqueue, int* data)
{
	LNODE* p;
	if (lqueue->front == NULL ||  lqueue->rear == NULL)		//判断是否队列为空,队空不能出队
		return ERROR;
	else if (lqueue->front == lqueue->rear)					//只有一个结点
	{
		p = lqueue->front;									//出队操作
		lqueue->front = lqueue->rear = NULL;				//队头队尾设置为空
	}
	else													//如果有多个结点
	{
		p = lqueue->front;									//出队操作
		lqueue->front = lqueue->front->next;				//队头向后移动
	}
	*data = p->data;										//获取出队列的值	
	__vcrt_free_normal(p);									//释放内存
	return OK;
}
(五)栈的应用
  1. 顺序栈的应用----括号匹配

    /*
    method:
    	匹配括号
    param:
    	exp		存放表达式的数组。例如char exp[] = "((a+b)*c)/d";  n为12
    	n		检查表达式的字节数目
    */
    int match(char exp[], int n)
    {
    	char stack[MAXSIZE];						//定义栈
    	int top = -1;								//定义栈头位置
    
    	for (int i = 0; i < n; i++)
    	{
    		if (exp[i] == '(')						//如果为 ( ,进栈
    		{
    			stack[++top] = '(';
    		}
    		else if (exp[i] == ')')					//如果为 )  出栈
    		{
    			if (top == (-1))					//如果栈为空
    				return ERROR;
    			else
    				--top;							//出栈
    		}
    	}
    	if (top == -1)								//如果最后栈为空,则匹配
    		return OK;
    	else
    		return ERROR;							//栈非空,不匹配
    }
    
  2. 链式栈的应用----后缀式的运算

    /*
    method:
    	根据操作符进行运算
    param:
    	a			数据a
    	operate		操作符
    	b			数据b
    */
    int OP(int a, char operate, int b)
    {													//判断操作符进行相关操作
    	if (operate == '+')			return a + b;	
    	else if (operate == '-')	return a - b;
    	else if (operate == '*')	return a * b;
    	else if (operate == '/')
    	{
    		if (b != 0)
    			return a / b;
    		else
    		{
    			printf("分母为0,错误!\n");
    			return ERROR;
    		}	
    	}
    }
    
    /*
    method:
    	计算后缀式
    param:
    	exp		存放后缀式的数组
    */
    int Compute(char exp[])
    {
    	int stack[MAXSIZE];								//定义栈
    	int top = -1;									//定义栈头位置
    	char op;										//用于接收运算符
    	char num1, num2, num3;							//取出栈中的值
    	for (int i = 0; exp[i] != '\0'; i++)
    	{
    		if ((exp[i]-'0') >= 0 && (exp[i]-'0') <= 9)
    		{
    			stack[++top] = exp[i] - '0';	//字符与整形之间转化
    		}
    		else
    		{
    			op = exp[i];							//获得运算符
    			num1 = stack[top--];					//取出最后一个值
    			num2 = stack[top--];					//取出倒数第二个值
    			num3 = OP(num2, op, num1);				//计算出num3
    			stack[++top] = num3;					//将num3入栈
    		}
    	}
    	return stack[top];								//返回最终的数值
    }
    
  3. 队列的应用

    • 队列在计算机系统的应用

      • 解决主机和外部设备之间速度不匹配问题

        仅以主机和打印机之间速度不匹配为例。主机输出速度较快,打印机速度较慢,因此需要将打印的数据存放到打印缓冲区,打印机按照先进先出的顺序依次取出要打印的数据,打印完再去发送请求。

      • 解决多用户引起的资源竞争问题

        在一个带有多终端的系统中,有多个用户需要根据CPU各自运行程序,它们向操作系统提出占用CPU的请求,操作系统将这些请求按照先后顺序存放到队列中,每次把CPU分给队首请求的用户,运行一段时间后,令其出队,依次进行。

(六)特殊矩阵的压缩存储
  1. 对称矩阵

    /*							
    method:
    	对称矩阵的压缩存储----下三角			 
    param:
    	matrices	要压缩存储的二维矩阵
    	row			矩阵的行数
    	colomn		矩阵的列数
    	str			压缩存储的数组
    */
    
    /*
    	公式:如果为下三角,
    	下标从(0,0)开始,
    	k = ( i*(i+1) / 2 + j )		i >= j
    	k = ( j*(j+1) / 2 + i )		i < j
    	如果从(1,1)开始
    	k = ( i*(i-1) / 2 + j-1 )	i >= j
    	k = ( j*(j-1) / 2 + i-1 )	i <= j
    
    */
    
    /*对称矩阵例子
    int Symmetry[3][3] = {	{1,	2,	3},
    						{2,	4,	5},
    						{3,	5,	8} };
    */
    void Sym_Mat(int matrices[][3],int row,int colomn,int str[])
    {
    	int i_row = 0, i_col = 0;	
    	int num = 0;
    	for (i_row; i_row < row; ++i_row)
    	{
    		i_col = 0;
    		for (i_col; i_col < colomn; ++i_col)
    		{
    			if (i_row >= i_col)
    				num = i_row * (i_row + 1) / 2 + i_col ;
    			else
    				num = i_col * (i_col + 1) / 2 + i_row ;
    
    			str[num] = matrices[i_row][i_col];
    			
    		}
    		
    	}
    }
    
  2. 下三角矩阵

    /*
    method:
    	对称矩阵的压缩存储----下三角矩阵
    param:
    	matrices	要压缩存储的二维矩阵
    	row			矩阵的行数
    	colomn		矩阵的列数
    	str			压缩存储的数组
    */
    
    /*
    	公式同对称矩阵相同,唯一的区别就是将其他的相同元素存放到了数组的最后位置
    */
    
    /*下三角矩阵例子
    int Triangular[3][3] = {	{1,	1,	1},
    							{2,	4,	1},
    							{3,	5,	8} };
    */	
    void Tri_Mat(int matrices[][3], int row, int colomn, int str[])
    {
    	int i_row = 0, i_col = 0;
    	int num = 0;
    	for (i_row; i_row < row; ++i_row)							//遍历每一行
    	{
    		i_col = 0;
    		for (i_col; i_col < colomn; ++i_col)					//遍历每一列
    		{
    			if (i_row >= i_col)
    				num = i_row * (i_row + 1) / 2 + i_col;			//计算存储位置	
    			//else
    				//num = i_col * (i_col + 1) / 2 + i_row;		//这里不存储
    
    			str[num] = matrices[i_row][i_col];					//按照公式存放到对应数组的位置
    		}
    	}
    	str[num + 1] = matrices[0][colomn - 1];						//将下三角矩阵的上方元素C存放到最后一个元素
    
    }
    
  3. 三对角矩阵

    /*
    method:
    	对称矩阵的压缩存储----三对角矩阵
    param:
    	matrices	要压缩存储的二维矩阵
    	row			矩阵的行数
    	colomn		矩阵的列数
    	str			压缩存储的数组
    */
    /*
    	公式
    	下标从(0,0)开始,
    	k = 2i + j                 	(| i-j | <= 1)
    	下标从(1,1)开始,
    	k = 2(i-1) + j - 1			 (| i-j | <= 1)
    */
    /*三对角矩阵的例子
    int Opposite[4][4] = {		{1,	2,	1,	1},
    							{3,	4,	5,	1},
    							{1,	6,	7,	8},
    							{1,	1,	9,	10} };
    */
    void Opp_Mat(int matrices[][4], int row, int colomn, int str[])
    {
    	int i_row = 0, i_col = 0;
    	int num = 0;
    	for (i_row; i_row < row; ++i_row)							//遍历每一行
    	{
    		i_col = 0;
    		for (i_col; i_col < colomn; ++i_col)					//遍历每一列
    		{
    			if (abs(i_row - i_col) <= 1)
    			{													
    				num = 2 * i_row + i_col;						//计算存储位置
    				str[num] = matrices[i_row][i_col];				//按照公式存放到对应数组的位置
    			}
    		}
    	}
    	str[num + 1] = matrices[0][colomn - 1];						//将C给最后一个元素
    }
    
发布了46 篇原创文章 · 获赞 75 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/UNIONDONG/article/details/98670006
今日推荐