数据结构-线性结构(链表、栈、队列)实现
公共头文件common.h
#define TRUE 1
#define FALSE 0// 定义节点数据类型
#define DATA_TYPE int
单链表C语言实现
SingleList.h
#pragma once#include "common.h"typedef struct Node
{DATA_TYPE data;struct Node *next;
} Node;Node *initList();void headInsert(Node *L, DATA_TYPE data);void tailInsert(Node *L, DATA_TYPE data);int contains(Node *L, DATA_TYPE data);int list_delete(Node *L, DATA_TYPE data);void printList(Node *L);void test_SingleList();int size(Node *L);
SingleList.c
#include <stdio.h>
#include <stdlib.h>#include "SingleList.h"// 头结点 链表的第一个节点 通常不存储实际的数据元素 用于简化操作、管理链表
// 首节点 头结点之后的第一个节点 链表中第一个存储实际数据的节点
Node *initList()
{Node *head = malloc(sizeof(Node));head->data = 0;head->next = NULL;return head;
}// 头插法
void headInsert(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;node->next = L->next;L->next = node;L->data++;
}// 尾插法 需要遍历整个链表找到尾结点
void tailInsert(Node *L, DATA_TYPE data)
{Node *p_tmp = L;while (p_tmp->next != NULL) // 找到尾结点{p_tmp = p_tmp->next;}Node *node = malloc(sizeof(Node));node->data = data;node->next = NULL;p_tmp->next = node;L->data++;
}int contains(Node *L, DATA_TYPE data)
{Node *p_tmp = L;while (p_tmp->next != NULL && p_tmp->next->data != data){p_tmp = p_tmp->next;}if (p_tmp->next == NULL){return FALSE;}return TRUE;
}int list_delete(Node *L, DATA_TYPE data)
{Node *preNode = L;Node *node = L->next;while (node){if (node->data == data){preNode->next = node->next; // 删除节点free(node); // 释放节点占用内存L->data--; // 链表节点数减一return TRUE;}preNode = node; // 保存前一个节点指针node = node->next;}return FALSE;
}void printList(Node *L)
{Node *node = L->next;while (node){printf("%d -> ", node->data);node = node->next;}printf("NULL\n");
}int size(Node *L)
{return L->data;
}void test_SingleList()
{Node *head = initList();headInsert(head, 1);headInsert(head, 2);headInsert(head, 3);tailInsert(head, 4);tailInsert(head, 5);tailInsert(head, 6);printf("contains: %d\n", contains(head, 1));printf("contains: %d\n", contains(head, 6));printf("size: %d\n", size(head));printList(head);printf("\n");list_delete(head, 4);list_delete(head, 6);printf("size: %d\n", size(head));printList(head);
}
单链表Java实现
public class SingleList {private int size; // 保存节点个数private Node head;public SingleList() {head = new Node(0); // 头结点数据域保存节点个数 与 size等价}public void headInsert(int data) {Node node = new Node(data, head.next);head.next = node;head.data++;size++;}public void tailInsert(int data) {Node tmp = head;while (tmp.next != null) { // 找到尾结点tmp = tmp.next;}Node node = new Node(data);tmp.next = node;size++;head.data++;}public boolean contains(int data) {Node tmp = head;while (tmp.next != null && tmp.data != data) {tmp = tmp.next;}if (tmp.next == null) {return false;}return true;}public boolean delete(int data) { // Java LinkedList包含节点前后引用Node preNode = head; // 保存删除节点的前一个节点Node node = head.next;while (node != null) {if (node.data == data) { // 要删除的节点preNode.next = node.next;size--;head.data--;return true;}preNode = node;node = node.next;}return false;}public void printList() {Node node = head.next;while (node != null) {System.out.print(node.data + " -> ");node = node.next;}}public int size() {
// return size;return head.data;}/*** 单链表节点类*/private static class Node {int data;Node next;public Node(int data) {this.data = data;}public Node(int data, Node next) {this.data = data;this.next = next;}}public static void main(String[] args) {SingleList list = new SingleList();list.headInsert(1);list.headInsert(2);list.headInsert(3);list.tailInsert(4);list.tailInsert(5);list.tailInsert(6);System.out.println(list.contains(1));System.out.println(list.contains(6));System.out.println("size: " + list.size());list.printList();System.out.println();list.delete(4);list.delete(6);System.out.println("size: " + list.size());list.printList();}
}
循环单链表
LoopSingleList.h
#pragma once#include "common.h"typedef struct Node
{DATA_TYPE data;struct Node *next;
} Node;Node *initList();void headInsert(Node *L, DATA_TYPE data);void tailInsert(Node *L, DATA_TYPE data);int list_delete(Node *L, DATA_TYPE data);void printList(Node *L);int size(Node *L);void test_loop_singleList();
LoopSingleList.c
#include <stdio.h>
#include <stdlib.h>#include "LoopSingleList.h"Node *initList()
{Node *head = malloc(sizeof(Node));head->data = 0;head->next = head;return head;
}void headInsert(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;node->next = L->next;L->next = node;L->data++;
}void tailInsert(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;Node *head = L;while (head->next != L){head = head->next;}node->next = L;head->next = node;L->data++;
}int list_delete(Node *L, DATA_TYPE data)
{Node *preNode = L;Node *node = L->next;while (node != L){if (node->data == data){preNode->next = node->next;free(node);L->data--;return TRUE;}preNode = node;node = node->next;}return FALSE;
}void printList(Node *L)
{Node *node = L->next;while (node != L){printf("%d -> ", node->data);node = node->next;}printf("(首节点)%d", node->next->data);
}int size(Node *L)
{return L->data;
}void test_loop_singleList()
{Node *head = initList();headInsert(head, 1);headInsert(head, 2);headInsert(head, 3);tailInsert(head, 4);tailInsert(head, 5);tailInsert(head, 6);printf("size: %d\n", size(head));printList(head);printf("\n");list_delete(head, 4);list_delete(head, 6);printf("size: %d\n", size(head));printList(head);
}
双链表
DoubleList.h
#include "common.h"typedef struct Node
{DATA_TYPE data;struct Node *pre;struct Node *next;
} Node;Node *initList();void headInsert(Node *L, DATA_TYPE data);void tailInsert(Node *L, DATA_TYPE data);int list_delete(Node *L, DATA_TYPE data);void printList(Node *L);int size(Node *L);void test_double_list();
DoubleList.c
#include <stdio.h>
#include <stdlib.h>#include "DoubleList.h"Node *initList()
{Node *head = malloc(sizeof(Node));head->data = 0;head->pre = NULL;head->next = NULL;return head;
}void headInsert(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;node->pre = L;node->next = L->next;if (L->next){L->next->pre = node;L->next = node;}else // 首次插入 L->next=NULL{L->next = node;}L->data++;
}void tailInsert(Node *L, DATA_TYPE data)
{Node *tail = L;while (tail->next){tail = tail->next;}Node *node = malloc(sizeof(Node));node->data = data;node->pre = tail;node->next = tail->next; // NULLtail->next = node;L->data++;
}int list_delete(Node *L, DATA_TYPE data)
{Node *head = L->next;while (head){if (head->data == data){if (head->next) // 如果不是尾结点{head->next->pre = head->pre;}head->pre->next = head->next;free(head);L->data--;return TRUE;}head = head->next;}return FALSE;
}void printList(Node *L)
{Node *node = L->next;while (node){printf("%d -> ", node->data);node = node->next;}printf("NULL\n");
}int size(Node *L)
{return L->data;
}void test_double_list()
{Node *head = initList();headInsert(head, 1);headInsert(head, 2);headInsert(head, 3);tailInsert(head, 4);tailInsert(head, 5);tailInsert(head, 6);printf("size: %d\n", size(head));printList(head);printf("\n");list_delete(head, 3); // 首节点list_delete(head, 4); // 中间节点list_delete(head, 6); // 尾结点printf("size: %d\n", size(head));printList(head);
}
循环双链表
LoopDoubleList.c
#include <stdio.h>
#include <stdlib.h>#include "DoubleList.h"Node *initList()
{Node *head = malloc(sizeof(Node));head->data = 0;head->pre = head;head->next = head;return head;
}void headInsert(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;node->pre = L;node->next = L->next;L->next->pre = node;L->next = node;L->data++;
}void tailInsert(Node *L, DATA_TYPE data)
{Node *tail = L;while (tail->next != L){tail = tail->next;}Node *node = malloc(sizeof(Node));node->data = data;node->pre = tail;node->next = tail->next;tail->next = node;L->data++;
}int list_delete(Node *L, DATA_TYPE data)
{Node *head = L->next;while (head != L){if (head->data == data){head->next->pre = head->pre;head->pre->next = head->next;free(head);L->data--;return TRUE;}head = head->next;}return FALSE;
}void printList(Node *L)
{Node *node = L->next;while (node != L){printf("%d -> ", node->data);node = node->next;}printf("NULL\n");
}int size(Node *L)
{return L->data;
}void test_double_list()
{Node *head = initList();headInsert(head, 1);headInsert(head, 2);headInsert(head, 3);tailInsert(head, 4);tailInsert(head, 5);tailInsert(head, 6);printf("size: %d\n", size(head));printList(head);list_delete(head, 3); // 首节点list_delete(head, 4); // 中间节点list_delete(head, 6); // 尾结点printf("size: %d\n", size(head));printList(head);
}
栈-链表实现
ListStack.h
#include "common.h"typedef struct Node
{DATA_TYPE data;struct Node *next;
} Node;Node *initStack();void push(Node *L, DATA_TYPE data);DATA_TYPE pop(Node *L);int is_empty(Node *L);void printStack(Node *L);void test_List_Stack();
ListStack.c
#include <stdio.h>
#include <stdlib.h>#include "listStack.h"Node *initStack()
{Node *head = malloc(sizeof(Node));head->data = 0;head->next = NULL;return head;
}void push(Node *L, DATA_TYPE data)
{Node *node = malloc(sizeof(Node));node->data = data;node->next = L->next;L->next = node;L->data++;
}DATA_TYPE pop(Node *L)
{if (L->next){Node *node = L->next;DATA_TYPE data = node->data;L->next = node->next;free(node); // 释放首节点内存L->data--;return data;}return 0;
}int is_empty(Node *L)
{return L->data == 0;
}void printStack(Node *L)
{Node *head = L->next;while (head){printf("%d -> ", head->data);head = head->next;}printf("NULL\n");
}void test_List_Stack()
{Node *stack = initStack();printf("is_empty: %d\n", is_empty(stack));push(stack, 1);push(stack, 2);push(stack, 3);push(stack, 4);printf("is_empty: %d\n", is_empty(stack));printStack(stack);pop(stack);printStack(stack);
}
栈-数组实现
ArrayStack.h
#include "common.h"void initStack();void push(DATA_TYPE data);DATA_TYPE pop();DATA_TYPE top();int is_empty();void printStack();void destroy_stack();void test_Array_Stack();
ArrayStack.c
#include <stdio.h>
#include <stdlib.h>#include "ArrayStack.h"static size_t size; // 栈大小
static DATA_TYPE *stack; // 数组表示
static int index = -1; // 栈顶指针void initStack(size_t stack_size)
{size = stack_size;stack = malloc(sizeof(DATA_TYPE) * size);
}void push(DATA_TYPE data)
{stack[++index] = data;
}DATA_TYPE pop()
{if (is_empty()){perror("空栈...\n");exit(1);}return stack[index--];
}DATA_TYPE top()
{return stack[index];
}int is_empty()
{return index == -1;
}void printStack()
{for (int i = index; i >= 0; i--){printf("%d ", stack[i]);}printf("\n");
}void destroy_stack()
{size = 0;free(stack);stack = NULL;
}void test_Array_Stack()
{initStack(10);printf("is_empty: %d\n", is_empty());push(1);push(2);push(3);push(4);printf("is_empty: %d\n", is_empty());printStack();printf("pop: %d\n", pop());printf("top: %d\n", top());printStack();destroy_stack();
}
队列-双链表实现
ListQueue.h
#pragma once#include "common.h"typedef struct Node
{DATA_TYPE data;struct Node *pre;struct Node *next;
} Node;Node *initQueue();void enQueue(Node *L, DATA_TYPE data);void deQueue(Node *L);void printQueue(Node *L);void test_List_Queue();
ListQueue.c
#include <stdio.h>
#include <stdlib.h>#include "ListQueue.h"Node *initQueue()
{Node *head = malloc(sizeof(Node));head->data = 0;head->pre = NULL;head->next = NULL;return head;
}void enQueue(Node *L, DATA_TYPE data)
{Node *head = L;while (head->next){head = head->next;}Node *node = malloc(sizeof(Node));node->data = data;node->pre = head;node->next = head->next;head->next = node;L->data++;
}void deQueue(Node *L)
{Node *node = L->next;L->next = node->next;node->next->pre = L;free(node);L->data--;
}void printQueue(Node *L)
{Node *node = L;while (node->next){printf("%d <- ", node->next->data);node = node->next;}printf("NULL\n");
}void test_List_Queue()
{Node *head = initQueue();enQueue(head, 1);enQueue(head, 2);enQueue(head, 3);enQueue(head, 4);printQueue(head);deQueue(head);deQueue(head);printQueue(head);
}
循环队列
ArrayCircularQueue.h
#include <stdlib.h>#include "common.h"typedef struct Queue
{DATA_TYPE *data;int front;int rear;
} Queue;Queue *initQueue(size_t size);void enQueue(Queue *Q, DATA_TYPE value);DATA_TYPE deQueue(Queue *Q);int isFull(Queue* Q);int isEmpty(Queue* Q);void printQueue(Queue *Q);void test_Array_Queue();
ArrayCircularQueue.c
#include <stdio.h>
#include <stdlib.h>#include "ArrayCircularQueue.h"/**
* 当普通队列的尾指针达到存储空间的末尾时,即使队列前方仍有空位,也无法继续存储新元素,这就是假溢出现象。
* 循环队列通过将存储空间视为环状来解决这一问题,使得当队尾指针到达末尾时,可以循环回到存储空间的开头继续存储元素。
*/static size_t queue_size = -1;Queue *initQueue(size_t size)
{Queue *Q = malloc(sizeof(Queue));queue_size = size;Q->data = malloc(sizeof(DATA_TYPE) * size);Q->front = Q->rear = 0;return Q;
}void enQueue(Queue *Q, DATA_TYPE value)
{if (isFull(Q))return;Q->data[Q->rear] = value;Q->rear = (Q->rear + 1) % queue_size;
}DATA_TYPE deQueue(Queue *Q)
{if (isEmpty(Q)){perror("空队列...");exit(1);}DATA_TYPE val = Q->data[Q->front];Q->front = (Q->front + 1) % queue_size;return val;
}int isFull(Queue *Q)
{return (Q->rear + 1) % queue_size == Q->front;
}int isEmpty(Queue *Q)
{return Q->front == Q->rear; // 初始化时 队列为空
}void printQueue(Queue *Q)
{// 获取队列长度:队列中有多少个元素int len = (Q->rear - Q->front + queue_size) % queue_size;int index = Q->front;for (int i = 0; i < len; i++){printf("%d <- ", Q->data[index]);index = (index + 1) % queue_size;}printf("NULL\n");
}void test_Array_Queue()
{Queue *Q = initQueue(5);enQueue(Q, 1);enQueue(Q, 2);enQueue(Q, 3);enQueue(Q, 4);printf("isFull: %d\n", isFull(Q));enQueue(Q, 4);printf("isFull: %d\n", isFull(Q));printQueue(Q);deQueue(Q);deQueue(Q);printQueue(Q);
}
总结
栈:适用于需要后进先出的场景,如函数调用栈、表达式求值等。
队列:适用于需要先进先出的场景,如任务调度、消息队列等。
链表:适用于频繁插入和删除元素的场景,如链表实现的动态内存管理。
顺序表:一种以数组形式实现的线性结构,具有随机访问的特点。元素在内存中是连续存储的,支持快速的元素访问,但插入和删除操作需要移动多个元素。