一、数据结构的基本概念
1、逻辑结构,数据间的逻辑关系
(1) 集合机构: 集 结构中的数据元素除了“属于同一个集合”之外,没有任何关系
(2) 线性结构: 表 结构中的数据元素具有一对一的前后关系
(3) 树型结构: 树 结构中的数据元素具有一对多的父子关系
(4) 网状结构: 图 结构中的数据元素具有多对多的交叉映射关系
2、物理结构, 数据的存储
(1) 顺序结构: 结构中的数据元素存放在一段连续的地址空间中,随机访问方便,空间利用率低,插入删除不便.
(2) 链式结构: 结构中的数据元素存放在彼此独立的地址空间中, 每个独立的空间被称为节点,节点除了保存数据以外,还保存另一个或几个相关节点的地址, 空间利用率高, 插入删除方便, 随机访问不便.
顺序结构和链式结构互补, 优点和缺点相反
3、逻辑结构与物理结构关系
表 | 树 | 图 | |
---|---|---|---|
顺序 | 数组 | 顺序树 | 复合 |
链式 | 链表 | 链式树 |
二、数据结构的基本运算
1、创建/销毁
2、插入/删除
3、获取/修改
4、排序/查找
三、数据结构的基本实现
1、堆栈
(1) 基本特征: 后进先出 (像个一边开口的桶)
(2) 基本操作: 压入(push)、弹出(pop)
(3) 实现要点: 初始化空间、栈顶指针、判空判满
范例:
A、用数组方式实现
// .h
// 基于数组的堆栈
#ifndef _SA_H
#define _SA_H
#include <sys/types.h>
using namespace std;
// 堆栈
typedef struct Stack
{
int* arr; // 数组
size_t cap; // 容量
size_t top; // 栈顶
} STACK;
// 分配内存并初始化为空堆栈
void stack_init(STACK* stack, size_t cap);
// 释放内存并恢复到初始状态
void stack_deinit(STACK* stack);
// 判断是否满
int stack_full(STACK* stack);
// 判断是否为空
int stack_empty(STACK* stack);
// 压入
void stack_push(STACK* stack, int data);
// 弹出
int stack_pop(STACK* stack);
// 栈顶
int stack_top(STACK* stack);
// 数量
int stack_size(STACK* stack);
#endif
// .c
#include <stdlib.h>
#include "textC.h"
// 分配内存并初始化为空堆栈
void stack_init(STACK* stack, size_t cap)
{
stack->arr = (int*)malloc (cap * sizeof(int));
stack->cap = cap;
stack->top = 0;
}
// 释放内存并恢复到初始状态
void stack_deinit(STACK* stack)
{
free(stack->arr);
stack->arr = NULL;
stack->cap = 0;
stack->top = 0;
}
// 判断是否满
int stack_full(STACK* stack)
{
return stack->top >= stack->cap;
}
// 判断是否为空
int stack_empty(STACK* stack)
{
return ! stack->top;
}
// 压入
void stack_push(STACK* stack, int data)
{
stack->arr[stack->top++] = data;
}
// 弹出
int stack_pop(STACK* stack)
{
return stack->arr[--stack->top];
}
// 栈顶
int stack_top(STACK* stack)
{
return stack->arr[stack->top - 1];
}
// 数量
int stack_size(STACK* stack)
{
return stack->top;
}
int main(void)
{
STACK stack;
stack_init(&stack, 10);
int i = 0;
while(!stack_full(&stack))
{
stack_push(&stack, i++);
}
printf("size = %d\n", stack_size(&stack));
while(!stack_empty(&stack))
{
printf("%d\n", stack_pop(&stack));
}
stack_deinit(&stack);
return 0;
}
B、用链表方式实现
// .h
// 基于数组的堆栈
#ifndef _SL_H
#define _SL_H
#include <sys/types.h>
// 节点
typedef struct StackNode {
int data; // 数据
struct StackNode* next; // 后指针
} STACK_NODE;
// 堆栈
typedef struct Stack
{
STACK_NODE* top; // 栈顶
} STACK;
// 初始化为空堆栈
void stack_init(STACK* stack);
// 释放剩余节点并恢复到初始状态
void stack_deinit(STACK* stack);
// 判断是否为空
int stack_empty(STACK* stack);
// 压入
void stack_push(STACK* stack, int data);
// 弹出
int stack_pop(STACK* stack);
// 栈顶
int stack_top(STACK* stack);
// 数量
int stack_size(STACK* stack);
#endif
// .c
#include <stdlib.h>
#include "textC.h"
// 创建节点
static STACK_NODE* create_node(int data, STACK_NODE* next)
{
STACK_NODE* node = (STACK_NODE*)malloc (sizeof (STACK_NODE));
node->data = data;
node->next = next;
return node;
}
// 销毁节点
static STACK_NODE* destroy_node(STACK_NODE* node)
{
STACK_NODE* next = node->next;
free(node);
return next;
}
// 初始化为空堆栈
void stack_init(STACK* stack)
{
stack->top = NULL;
}
// 释放剩余节点并恢复到初始状态
void stack_deinit(STACK* stack)
{
while (stack->top)
{
stack->top = destroy_node(stack->top);
}
}
// 判断是否为空
int stack_empty(STACK* stack)
{
return ! stack->top;
}
// 压入
void stack_push(STACK* stack, int data)
{
stack->top = create_node(data, stack->top);
}
// 弹出
int stack_pop(STACK* stack)
{
int data = stack->top->data;
stack->top = destroy_node(stack->top);
return data;
}
// 栈顶
int stack_top(STACK* stack)
{
return stack->top->data;
}
// 数量
int stack_size(STACK* stack)
{
int count = 0;
STACK_NODE* node = NULL;
for (node = stack->top; node; node = node->next) {
++count; // 前++ 比 后++ 效率高, 因为后运算要返回历史值,需要拷贝副本.而前++只需返回值本身
}
return count;
}
int main(void)
{
STACK stack;
stack_init(&stack);
int i = 0;
while(i < 10)
{
stack_push(&stack, i++);
}
printf("size = %d\n", stack_size(&stack));
while(!stack_empty(&stack))
{
printf("%d\n", stack_pop(&stack));
}
stack_deinit(&stack);
return 0;
}
C、输入一个整数和进制数, 以该进制打印该数
#include <stdio.h>
#include "cstack.h"
// 输入一个整数和进制数, 以该进制打印该数
int main(void)
{
printf("please enter a num : ");
unsigned int num;
scanf("%d", &num);
printf("please enter 进制 : ");
int base;
scanf("%d", &base);
STACK stack;
stack_init(&stack);
do {
stack_push(&stack, num % base);
} while( num /= base );
printf("The result is : \n");
while (! stack_empty(&stack))
{
int digit = stack_pop(&stack);
if (digit >= 10)
{
printf("%c", digit-10+'A');
}
else {
printf("%d", digit);
}
}
printf("\n");
stack_deinit(&stack);
return 0;
}
2、队列
(1) 基本特征: 先进先出(FIFO) (像管道)
(2) 基本操作: 压入(push)、弹出(pop)
(3) 实现要点: 初始化空间、前指针front弹出, 后指针rear压入、循环使用、判空判满
范例:
A、用数组方式实现
// .h
// 基于数组的队列
#ifndef _Q_H
#define _Q_H
#include <sys/types.h>
typedef struct Queue
{
int* arr; // 数组
size_t cap; // 容量
size_t front; // 前端, 弹出
size_t rear; // 后端, 压入
size_t size; // 数量
} QUEUE;
// 分配内存并初始化为空队列
void queue_init(QUEUE* queue, size_t cap);
// 释放内存并恢复到初始状态
void queue_deinit(QUEUE* queue);
// 判断是否满
int queue_full(QUEUE* queue);
// 判断是否空
int queue_empty(QUEUE* queue);
// 压入
void queue_push(QUEUE* queue, int data);
// 弹出
int queue_pop(QUEUE* queue);
// 队首
int queue_front(QUEUE* queue);
// 数量
size_t queue_size(QUEUE* queue);
#endif
// .c
#include <stdio.h>
#include <stdlib.h>
#include "cqueue.h"
// 分配内存并初始化为空队列
void queue_init(QUEUE* queue, size_t cap)
{
queue->arr = (int *)malloc(sizeof (int) * cap);
queue->cap = cap;
queue->front = queue->rear = 0;
queue->size = 0;
}
// 释放内存并恢复到初始状态
void queue_deinit(QUEUE* queue)
{
free(queue->arr);
queue->arr = NULL;
queue->cap = 0;
queue->front = queue->rear = 0;
queue->size = 0;
}
// 判断是否满
int queue_full(QUEUE* queue)
{
return queue->size >= queue->cap;
}
// 判断是否空
int queue_empty(QUEUE* queue)
{
return ! queue->size;
}
// 压入
void queue_push(QUEUE* queue, int data)
{
if (queue->rear >= queue->cap) {
queue->rear = 0;
}
++queue->size;
queue->arr[queue->rear++] = data;
}
// 弹出
int queue_pop(QUEUE* queue)
{
if (queue->front >= queue->cap) {
queue->front = 0;
}
--queue->size;
return queue->arr[queue->front++];
}
// 队首
int queue_front(QUEUE* queue)
{
if (queue->front >= queue->cap) {
queue->front = 0;
}
return queue->arr[queue->front];
}
// 数量
size_t queue_size(QUEUE* queue)
{
return queue->size;
}
#include <stdio.h>
#include "cqueue.h"
int main(void)
{
QUEUE queue;
queue_init(&queue, 4);
queue_push(&queue, 10);
queue_push(&queue, 20);
queue_push(&queue, 30);
queue_push(&queue, 40);
printf("%s\n", queue_full(&queue) ? "满" : "不满");
printf("%d\n", queue_pop(&queue)); // 10
printf("%d\n", queue_pop(&queue)); // 20
queue_push(&queue, 50);
queue_push(&queue, 60);
printf("%d\n", queue_pop(&queue)); // 30
printf("%d\n", queue_pop(&queue)); // 40
printf("%d\n", queue_pop(&queue)); // 50
printf("%d\n", queue_pop(&queue)); // 60
printf("%s\n", queue_empty(&queue) ? "空" : "不空");
queue_deinit(&queue);
return 0;
}
B、用链表方式实现
// .h
#ifndef _Q_H
#define _Q_H
#include <sys/types.h>
// 基于链表的队列
typedef struct QueueNode
{
int data; // 数据
struct QueueNode* next; // 后指针
} QUEUE_NODE;
typedef struct Queue
{
QUEUE_NODE* front; // 前端 弹出
QUEUE_NODE* rear; // 后端 压入
} QUEUE;
// 初始化为空队列
void queue_init(QUEUE* queue);
// 释放内剩余节点并恢复到初始状态
void queue_deinit(QUEUE* queue);
// 判断是否空
int queue_empty(QUEUE* queue);
// 压入
void queue_push(QUEUE* queue, int data);
// 弹出
int queue_pop(QUEUE* queue);
// 队首
int queue_front(QUEUE* queue);
// 数量
size_t queue_size(QUEUE* queue);
#endif
// .c
#include <stdio.h>
#include <stdlib.h>
#include "cqueue.h"
// 创建节点
static QUEUE_NODE* create_node(int data)
{
QUEUE_NODE* node = (QUEUE_NODE*)malloc(sizeof(QUEUE_NODE));
node->data = data;
node->next = NULL;
return node;
}
// 销毁节点
static QUEUE_NODE* destroy_node(QUEUE_NODE* node)
{
QUEUE_NODE* next = node->next;
free(node);
return next;
}
// 分配内存并初始化为空队列
void queue_init(QUEUE* queue)
{
queue->front = queue->rear = NULL;
}
// 释放内存并恢复到初始状态
void queue_deinit(QUEUE* queue)
{
while (queue->front) {
queue->front = destroy_node(queue->front);
}
queue->rear = NULL;
}
// 判断是否空
int queue_empty(QUEUE* queue)
{
return ! queue->front && ! queue->rear;
}
// 压入
void queue_push(QUEUE* queue, int data)
{
QUEUE_NODE* node = create_node(data);
if (queue->rear) {
queue->rear->next = node;
}
else {
queue->front = node;
}
queue->rear = node;
}
// 弹出
int queue_pop(QUEUE* queue)
{
int data = queue->front->data;
queue->front = destroy_node(queue->front);
if (!queue->front) {
queue->rear = NULL;
}
return data;
}
// 队首
int queue_front(QUEUE* queue)
{
return queue->front->data;
}
// 数量
size_t queue_size(QUEUE* queue)
{
size_t size = 0;
QUEUE_NODE* node = NULL;
for (node = queue->front; node; node = node->next) {
++size;
}
return size;
}
#include <stdio.h>
#include "cqueue.h"
int main(void)
{
QUEUE queue;
queue_init(&queue);
for (int i = 0; i < 10; i++) {
queue_push(&queue, i*10);
}
printf("长度 = %zu\n", queue_size(&queue)); // 10
while (! queue_empty(&queue)) {
printf("%d\n", queue_pop(&queue));
}
queue_deinit(&queue);
return 0;
}
C、用堆栈的方式实现队列
创建两个堆栈, 一个用来输入, 一个用来输出. 将输入栈pop到输出栈. 最后再pop输出栈. 就可以实现队列的效果
// .h
// 基于堆栈的队列
#ifndef _SQ_H
#define _SQ_H
#include "cstack.h"
typedef struct Queue
{
STACK input;
STACK output;
} QUEUE;
// 初始化为空队列
void queue_init(QUEUE* queue);
// 释放内剩余节点并恢复到初始状态
void queue_deinit(QUEUE* queue);
// 判断是否空
int queue_empty(QUEUE* queue);
// 压入
void queue_push(QUEUE* queue, int data);
// 弹出
int queue_pop(QUEUE* queue);
// 队首
int queue_front(QUEUE* queue);
// 数量
size_t queue_size(QUEUE* queue);
#endif
// .c
#include <stdio.h>
#include <stdlib.h>
#include "cstack_queue.h"
// 分配内存并初始化为空队列
void queue_init(QUEUE* queue)
{
stack_init(&queue->input);
stack_init(&queue->output);
}
// 释放内存并恢复到初始状态
void queue_deinit(QUEUE* queue)
{
stack_deinit(&queue->input);
stack_deinit(&queue->output);
}
// 判断是否空
int queue_empty(QUEUE* queue)
{
return stack_empty(&queue->input) && stack_empty(&queue->output);
}
// 压入
void queue_push(QUEUE* queue, int data)
{
stack_push(&queue->input, data);
}
// 弹出
int queue_pop(QUEUE* queue)
{
if (stack_empty(&queue->output)) {
while(!stack_empty(&queue->input)) {
stack_push(&queue->output, stack_pop(&queue->input));
}
}
return stack_pop(&queue->output);
}
// 队首
int queue_front(QUEUE* queue)
{
if (stack_empty(&queue->output)) {
while(!stack_empty(&queue->input)) {
stack_push(&queue->output, stack_pop(&queue->input));
}
}
return stack_top(&queue->output);
}
// 数量
size_t queue_size(QUEUE* queue)
{
return stack_size(&queue->input) + stack_size(&queue->output);
}
#include <stdio.h>
#include "cstack_queue.h"
int main(void)
{
QUEUE queue;
queue_init(&queue);
int i;
for (i = 0; i < 10; i++) {
queue_push(&queue, i);
}
printf("长度 = %zu\n", queue_size(&queue));
printf("%d\n", queue_pop(&queue));
printf("%d\n", queue_pop(&queue));
printf("%d\n", queue_pop(&queue));
for (; i < 15; i++) {
queue_push(&queue, i);
}
while (! queue_empty(&queue)) {
printf("%d\n", queue_pop(&queue));
}
queue_deinit(&queue);
return 0;
}