线性结构(表)——C语言实现(关键代码)
1.表
1.1顺序表(存储结构)
1.设计数据结构
typedef struct Array
{
TYPE* base; // 数组首地址
size_t size; // 元素的个数
}Array;
2.分析所具备的算法
// 创建
Array* create_array(size_t len);
// 销毁
void destory_array(Array* arr);
// 访问
TYPE* access_array(Array* arr,int index);
// 查找
int find_array(Array* arr,TYPE data);
// 排序
void sort_array(Array* arr);
// 遍历
void show_array(Array* arr);
// 删除
bool delete_array(Array* arr,int index);
// 插入
bool insert_array(Array* arr,int index,TYPE data);
3.实现几个常用的算法
// 创建
Array* create_array(size_t len)
{
Array* arr = malloc(sizeof(Array));
arr->base = malloc(sizeof(TYPE)*len);
arr->size = len;
return arr;
}
// 访问
TYPE* access_array(Array* arr,int index)
{
if(index < 0 || index >= arr->size) return NULL;
return arr->base + index;
}
// 查找
int find_array(Array* arr,TYPE data)
{
for(int i=0; i<arr->size; i++)
{
if(data == arr->base[i])
return i;
}
return -1;
}
// 遍历
void show_array(Array* arr)
{
for(int i=0; i<arr->size; i++)
{
printf("%d ",arr->base[i]);
}
printf("\n");
}
// 删除
bool delete_array(Array* arr,int index)
{
if(index < 0 || index >= arr->size) return false;
for(int i=index; i<arr->size-1; i++)
{
arr->base[i] = arr->base[i+1];
}
return true;
}
// 插入
bool insert_array(Array* arr,int index,TYPE data)
{
if(index < 0 || index >= arr->size) return false;
for(int i=arr->size-1; i>index; i--)
{
arr->base[i] = arr->base[i-1];
}
arr->base[index] = data;
return true;
}
4.使用算法--main函数
Array* arr = create_array(20);
for(int i=0; i<100; i++)
{
TYPE* p = access_array(arr,i);
if(NULL != p)
*access_array(arr,i) = rand() % 100;
}
show_array(arr);
insert_array(arr,10,86);
show_array(arr);
1.2 链式表(存储结构)
每个元素都独立存储在内存中的任意位置,元素之间由指针指向来维护关系(元素中有一个数据域指针指,向自己的类型)
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
//创建节点
Node* creat_node(TYPE data)
{
Node* node=malloc(sizeof(Node));
node->data=data;
node->next=NULL;
return node;
}
typedef struct List
{
Node* head;
Node* tail;
size_t size;
}List;
//创建
List* creat_list(void)
{
List* list=malloc(sizeof(List));
list->head=NULL;
list->tail=NULL;
return list;
}
//尾添加
void tail_add_list(List* list,TYPE data)
{
Node* node=creat_node(data);
if(0==list->size)
{
list->head=node;
list->tail=node;
}
else
{
list->tail->next=node;
list->tail=node;
}
list->size++;
}
//头删除
bool head_del_list(List* list)
{
if(0>=list->size) return false;
Node* temp=list->head;
if(list->size==1)
{
list->tail=NULL;
}
else
list->head=temp->next;
free(temp);
list->size--;
return true;
}
//插入
bool insert_list(List* list,int index,TYPE data)
{
if(index < 0 || index >=list->size) return false;
if(index==0)
{
head_add_list(list,data);
return true;
}
Node* prev =list->head;
for(int i=0;i<index-1;i++)
{
prev=prev->next;
}
Node* node=creat_node(data);
node->next=prev->next;
prev->next=node;
list->size++;
return true;
}
//位置删除
bool delete_index_list(List* list,int index)
{
if(index<0||index>=list->size) return false;
if(0==index)
{
head_del_list(list);
}
else if(list->size==index+1)
tail_del_list(list);
else
{
Node* prev=list->head;
for(int i=0;i<index-1;i++)
{
prev=prev->next;
}
Node* node=prev->next;
prev->next=node->next;
free(node);
list->size--;
}
return true;
}
//值删除
bool delete_value_list(List* list,TYPE data)
{
if(data==list->head->data)
{
head_del_list(list);
return true;
}
Node* prev=list->head;
while(prev->next!=NULL)
{
if(prev->next->data==data)
{
Node* node=prev->next;
prev->next=node->next;
free(node);
list->size--;
return true;
}
prev=prev->next;
}
return false;
}
//排序
void sort_list(List* list)
{
for(Node* node=list->head;node->next!=NULL;node=node->next)
{
for(Node* node1=node->next;node1!=NULL;node1=node1->next)
{
if(node->data<node1->data)
{
TYPE temp=node->data;
node->data=node1->data;
node1->data=temp;
}
}
}
}
//遍历
void show_list(List* list)
{
for(Node* node=list->head;node!=NULL;node=node->next)
{
printf("%d ",node->data);
}
printf("\n");
}
int main()
{
List* list=creat_list();
for(int i=0;i<10;i++)
{
tail_add_list(list,rand()%100);
}
show_list(list);
delete_index_list(list,9);
delete_index_list(list,0);
show_list(list);
}
1.3 双向链表
元素分散存储在内存中任意位置,元素中有一个数据项用来记录下一个元素的地址,这种叫单向链表。如果元素中有两个数据项,一个用来记录下一个元素的地址,另一个记录上一个元素的地址,这种叫双向链表。
typedef struct Node
{
struct Node* prev; // 前一个元素
TYPE data; // 数据
struct Node* next; // 后一个元素
}Node;
// 创建节点
Node* creat_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->prev = NULL;
node->data = data;
node->next = NULL;
return node;
}
typedef struct List
{
Node* head;
Node* tail;
size_t size;
}List;
1.4 通用链表
void* 万能指针
void* 可以与任意类型的指针互换 int* =void* void* =int*
需要把链表的数据域换成void* 类型
注意:由于存储的类型不确定,因此类型的运算规则不确定,当需要使用到关系运算运算时,需要链表的使用者提供运算(提供一个函 数供链表调用),这种模式叫回调
void* 不能直接解引用,需要先转换成其它有效类型
// 设计链表节点
typedef struct Node
{
void* ptr; // 指向数据的首地址
struct Node* next; // 元素的下一个位置
}Node;
// 创建结点
Node* creat_node(void* ptr)
{
Node* node = malloc(sizeof(Node));
node->ptr = ptr;
node->next = NULL;
return node;
}
// 设计链表结构
typedef struct List
{
Node* head;
size_t size;
}List;
// 创建链表
List* creat_list(void)
{
List* list = malloc(sizeof(List));
list->head = NULL;
list->size = 0;
return list;
}
void show(const void* ptr)
{
const double* p = ptr;
printf("%lf ",*p);
}
// 遍历
void show_list(List* list,void (*show)(const void* ptr))
{
for(Node* i=list->head; NULL!=i; i=i->next)
{
show(i->ptr);
}
printf("\n");
}
int cmp(const void* ptr1,const void* ptr2)
{
const double *p1 = ptr1 , *p2 = ptr2;
if(*p1 > *p2)
return 1;
else if(*p1 < *p2)
return -1;
else
return 0;
}
typedef struct Student
{
size_t id;
char name[20];
float score;
}Student;
void add_stu(void)
{
Student* stu = malloc(sizeof(Student));
printf("请输入学生的学号、改名、成绩:");
scanf("%u %s %f",&stu->id,stu->name,&stu->score);
add_tail_list(list,stu);
}
void show_stu(void)
{
void show(const void* ptr)
{
const Student* stu = ptr;
printf("%u %s %g\n",stu->id,stu->name,stu->score);
}
show_list(list,show);
}
2.栈 (逻辑结构)
是一种功能受限的线性表,只有一个端口用于元素的进出
特点是先进后出(后进先出)
一般常用于表达式解析,内存管理(为函数的调用提供支持)
顺序栈(容量有限) 链式栈(容量无限)
2.1 顺序栈
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
typedef struct Stack
{
TYPE* arr; // 内存首地址
int len; // 栈的容量 typedef unsigned int size_t;
int top; // 栈顶下标
}Stack;
// 创建
Stack* creat_stack(size_t cal);
// 销毁
void destory_stack(Stack* stack);
// 入栈
bool push_stack(Stack* stack,TYPE data);
// 出栈
bool pop_stack(Stack* stack);
// 栈空
bool empty_stack(Stack* stack);
// 栈满
bool full_stack(Stack* stack);
// 栈顶
TYPE* top_stack(Stack* stack);
int main()
{
Stack* stack = creat_stack(15);
printf("开始入栈:");
for(int i=0; i<20; i++)
{
printf("入栈%s,",push_stack(stack,i)?"成功":"失败");
printf("栈顶:%d\n",*top_stack(stack));
}
printf("------------------------\n开始出栈:\n");
for(int i=0; i<15; i++)
{
printf("栈顶:%2d,",*top_stack(stack));
printf("出栈:%s\n",pop_stack(stack)?"成功":"失败");
}
}
// 创建
Stack* creat_stack(size_t cal)
{
Stack* stack = malloc(sizeof(Stack));
stack->arr = malloc(sizeof(TYPE)*cal);
stack->len = cal;
stack->top = -1;
return stack;
}
// 销毁
void destory_stack(Stack* stack)
{
free(stack->arr);
free(stack);
}
// 入栈
bool push_stack(Stack* stack,TYPE data)
{
if(full_stack(stack)) return false;
stack->arr[++stack->top] = data;
return true;
}
// 出栈
bool pop_stack(Stack* stack)
{
if(empty_stack(stack)) return false;
stack->top--;
return true;
}
// 栈空
bool empty_stack(Stack* stack)
{
return -1 == stack->top;
}
// 栈满
bool full_stack(Stack* stack)
{
return stack->top+1 >= stack->len;
}
// 栈顶
TYPE* top_stack(Stack* stack)
{
if(empty_stack(stack)) return NULL;
return stack->arr + stack->top;
}
2.2 链式栈
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
Node* creat_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
typedef struct Stack
{
Node* top;
size_t len;
}Stack;
3.队列(逻辑结构)
是一种功能受限的线性表,有两个端口进出元素,一个端口只能入队,另一个端口只能出队
特点 先进先出 常用于任务排队,如:数据池,生产者与消费者模型 树的层序遍历 图的遍历
3.1 顺序队列
1.创建队列 2.销毁队列 3.入队 4.出队 5.队头 6.队尾 7.队空
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
typedef struct Queue
{
TYPE* base;
int size; // 容量
int head; // 队头
int tall; // 队尾
int cnt; // 数量
}Queue;
// 创建
Queue* creat_queue(int len);
// 销毁
void destory_queue(Queue* queue);
// 队空
bool empty_queue(Queue* queue);
// 队满
bool full_queue(Queue* queue);
// 入队
bool push_queue(Queue* queue,TYPE data);
// 出队
bool pop_queue(Queue* queue);
// 队头
TYPE* head_queue(Queue* queue);
// 队尾
TYPE* tall_queue(Queue* queue);
int main()
{
Queue* queue = creat_queue(10);
for(int i=0; i<15; i++)
{
printf("入队%s,",push_queue(queue,i)?"成功":"失败");
printf("队尾:%d\n",*tall_queue(queue));
}
printf("---------------------\n");
for(int i=0; i<5; i++)
{
printf("队头:%d,",*head_queue(queue));
printf("出队%s\n",pop_queue(queue)?"成功":"失败");
}
printf("---------------------\n");
for(int i=77; i<88; i++)
{
printf("入队%s,",push_queue(queue,i)?"成功":"失败");
printf("队尾:%d\n",*tall_queue(queue));
}
}
// 创建
Queue* creat_queue(int len)
{
Queue* queue = malloc(sizeof(Queue));
queue->base = malloc(sizeof(TYPE)*len);
queue->head = queue->cnt = 0;
queue->tall = -1;
queue->size = len;
return queue;
}
// 销毁
void destory_queue(Queue* queue)
{
free(queue->base);
free(queue);
}
// 队空
bool empty_queue(Queue* queue)
{
return !queue->cnt;
}
// 队满
bool full_queue(Queue* queue)
{
return queue->cnt >= queue->size;
}
// 入队
bool push_queue(Queue* queue,TYPE data)
{
// 判断是队满
if(full_queue(queue)) return false;
// 回头
queue->tall = (queue->tall+1) % queue->size;
queue->base[queue->tall] = data;
queue->cnt++;
return true;
}
// 出队
bool pop_queue(Queue* queue)
{
// 判断是否队空
if(empty_queue(queue)) return false;
// 回头
queue->head = (queue->head+1) % queue->size;
queue->cnt--;
return true;
}
// 队头
TYPE* head_queue(Queue* queue)
{
if(empty_queue(queue)) return NULL;
return queue->base + queue->head;
}
// 队尾
TYPE* tall_queue(Queue* queue)
{
if(empty_queue(queue)) return NULL;
return queue->base + queue->tall;
}
3.2 链式队列
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
Node* crete_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
typedef struct Queue
{
Node* head;
Node* tail;
size_t size;
}Queue;