数字之间的关系可以从两个完全不同的角度进行描述
逻辑关系(逻辑结构)是数字之间的关系,与计算机无关
物理关系(物理结构)是存放数字的存储区之间的关系
逻辑结构有如下几种可能
1.集合结构:所有数字可以被看作一个整体
2.线性结构:可以用一条有顺序的线把所有数字连起来
3.树状结构:所有数字是从一个数字开始向一个方向扩展出来的,任何数字可以扩展出多个其他数字
4.网状结构:任何两个数字之间可以有直接的联系,所有数字之间的联系没有统一的方向
物理结构有如下两种
1.顺序结构:内存里的所有存储区连续排列,数组和动态分配内存都是顺序结构的例子,顺序结构里可以给每个存储区
指定一个编号,通过编号可以找到对应的存储区,通过编号直接找到存储区的方法叫随机访问能力
顺序结构里存储区个数很难改变,所以容易造成内存浪费,顺序结构不适合进行插入或删除操作
2.链式结构:由多个相互独立的存储区构成,任何两个存储区之间可以使用指针连接,链式物理结构里每个存储区都必须是一个结构体类型的存储区,它们叫做节点。
单向线性链式物理结构中任何两个节点之间都有前后顺序(任何节点里只有一个指针)
单向线性链式物理结构中最后一个节点里的指针必须是空指针,可以在线性链式物理结构最前面增加一个无效节点,这个节点叫做头节点,
在线性链式物理结构的最后面增加一个无效节点,这个节点叫尾节点。
链式物理结构本身并不支持随机访问能力,链式物理结构适合进行插入删除操作
/*
动态分配节点演示
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int num;
struct node *p_next;
} node;
int main()
{
int num = 0;
node *p_node = NULL, *p_tmp = NULL;
node head = {0}, tail = {0};
//准备一个空的链式物理结构
head.p_next = &tail;
while (1)
{
printf("请输入一个数字:");
scanf("%d", &num);
if (num < 0)
{
break;
}
//动态分配一个节点
p_node = (node *)malloc(sizeof(node));
if (!p_node)
{
continue;
}
p_node->num = num;
p_node->p_next = NULL;
for (p_tmp = &head;p_tmp != &tail;p_tmp = p_tmp->p_next)
{
node *p_first = p_tmp;
node *p_mid = p_first->p_next;
node *p_last = p_mid->p_next;
if (p_mid == &tail || p_mid->num > num)
{
//如果p_mid指针和尾节点捆绑
//或p_mid指针捆绑的节点里的
//数字比新数字大就应该把新
//节点插入到p_first和p_mid
//中间
p_first->p_next = p_node;
p_node->p_next = p_mid;
break;
}
}
}
//删除某个数字所在的节点
printf("请输入要删除的数字:");
scanf("%d", &num);
for (p_tmp = &head;p_tmp != &tail;p_tmp = p_tmp->p_next)
{
node *p_first = p_tmp;
node *p_mid = p_first->p_next;
node *p_last = p_mid->p_next;
if (p_mid != &tail && p_mid->num == num)
{
//p_mid指针没有和尾节点捆绑
//并且p_mid指针捆绑的节点里的
//数字就是要删除的数字
p_first->p_next = p_last;
free(p_mid);
p_mid = NULL;
break;
}
}
//把有效节点里的数字按顺序显示在屏幕上
for (p_tmp = &head;p_tmp != &tail;p_tmp = p_tmp->p_next)
{
node *p_first = p_tmp;
node *p_mid = p_first->p_next;
node *p_last = p_mid->p_next;
if (p_mid != &tail)
{
printf("%d ", p_mid->num);
}
}
printf("\n");
//释放所有有效节点
while (head.p_next != &tail)
{
node *p_first = &head;
node *p_mid = p_first->p_next;
node *p_last = p_mid->p_next;
//p_mid和第一个有效节点捆绑
p_first->p_next = p_last;
free(p_mid);
p_mid = NULL;
}
return 0;
}
数据结构包含一组存储区和操作该存储区的函数,函数提供了对存储区的操作方法
栈的特点:先进后出,后进先出
入栈: 负责把一个数字放到栈里
出栈: 负责从栈里获得一个数字
顺序存储的栈操作
typedef struct
{
int buf[SIZE];
int num; //有效数字个数
} stack;
//栈初始化函数
void stack_init(stack *p_stack)
{
p_stack->num = 0;
}
//栈的清理函数
void stack_deinit(stack *p_stack)
{
p_stack->num = 0;
}
//判断满的函数
int stack_full(const stack *p_stack)
{
return p_stack->num >= SIZE;
}
//判断空的函数
int stack_empty(const stack *p_stack) {
return !(p_stack->num);
}
//获得有效数字个数
int stack_size(const stack *p_stack)
{
return p_stack->num;
}
//向栈里增加数字的函数
void stack_push(stack *p_stack, int num)
{
p_stack->buf[p_stack->num] = num;
p_stack->num++;
}
//从栈里获得数字的函数(把数字从栈里删除)
int stack_pop(stack *p_stack)
{
int ret = p_stack->buf[p_stack->num - 1];
p_stack->num--;
return ret;
}
//从栈里获得数字的函数(不删除数字)
int stack_top(const stack *p_stack)
{
return p_stack->buf[p_stack->num - 1];
}
队列:先进先出,后进后出
顺序存储队列操作
typedef struct
{
int buf[SIZE];
int head/*最前面有效数字的下标*/;
int tail/*最后一个数字所在存储区后一个存储区的下标*/;
/*如果队列里没有数字则head等于tail*/
} queue;
void queue_init(queue *p_queue)
{
p_queue->head = 0;
p_queue->tail = 0;
}
//队列清理函数
void queue_deinit(queue *p_queue)
{
p_queue->head = 0;
p_queue->tail = 0;
}
//判断满的函数
int queue_full(const queue *p_queue)
{
return p_queue->tail - p_queue->head >= SIZE;
}
//判断空的函数
int queue_empty(const queue *p_queue)
{
return p_queue->head == p_queue->tail;
}
//获得数字个数的函数
int queue_size(const queue *p_queue)
{
return p_queue->tail - p_queue->head;
}
//向队列里加入数字的函数
int queue_push(queue *p_queue, int num)
{
if(queue_full(const queue *p_queue))
{
return 0;
}
if(p_queue->tail==SIZE)
{
p_queue->tail=0;
}
p_queue->buf[p_queue->tail] = num;
p_queue->tail++;
return 1;
}
//从队列里获得数字的函数(要删除数字)
int queue_pop(queue *p_queue,int *value)
{
if(queue_empty(const queue *p_queue))
{
return 0;
}
*value = p_queue->buf[p_queue->head];
p_queue->head++;
return 1;
}
//从队列里获得数字的函数(不删除数字)
int queue_front(const queue *p_queue,int *value)
{
if(queue_empty(const queue *p_queue))
{
return 0;
}
*value = p_queue->buf[p_queue->head];
return 1;
}