链表
链表是一种线性数据结构,其中元素不是存储在连续的内存位置,而是通过指针链接在一起。每个元素称为一个节点,包含数据部分和指向下一个节点的指针。
单向链表示例:
假设有一个链表包含三个节点:1 -> 2 -> 3 -> NULL
单向链表的C语言实现
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构
struct Node {
int data; // 数据部分
struct Node* next; // 指向下一个节点的指针
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (!newNode) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 在链表头部插入节点
void insertAtHead(struct Node** head, int data) {
struct Node* newNode = createNode(data); // 创建新节点
newNode->next = *head; // 新节点指向原来的头节点
*head = newNode; // 更新头节点为新节点
}
// 打印链表
void printList(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data); // 打印当前节点的数据
current = current->next; // 移动到下一个节点
}
printf("NULL\n"); // 表示链表结束
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 3); // 插入节点3
insertAtHead(&head, 2); // 插入节点2
insertAtHead(&head, 1); // 插入节点1
printf("链表: ");
printList(head);
// 记得释放内存
struct Node* temp;
while (head != NULL) {
temp = head;
head = head->next;
free(temp);
}
return 0;
}
栈(基于链表)
栈是一种后进先出(LIFO)的数据结构。我们可以使用链表来实现栈,其中链表的头部作为栈顶。
栈示例:
假设有一个栈包含三个元素:10 -> 20 -> 30 (30是栈顶)
基于链表的栈的C语言实现
#include <stdio.h>
#include <stdlib.h>
// 定义栈节点结构
struct StackNode {
int data; // 数据部分
struct StackNode* next; // 指向下一个节点的指针
};
// 创建新节点
struct StackNode* createStackNode(int data) {
struct StackNode* newNode = (struct StackNode*)malloc(sizeof(struct StackNode));
if (!newNode) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 检查栈是否为空
int isEmpty(struct StackNode* root) {
return !root;
}
// 入栈操作
void push(struct StackNode** root, int data) {
struct StackNode* stackNode = createStackNode(data); // 创建新节点
stackNode->next = *root; // 新节点指向原来的栈顶
*root = stackNode; // 更新栈顶为新节点
printf("%d 已入栈\n", data);
}
// 出栈操作
int pop(struct StackNode** root) {
if (isEmpty(*root)) {
printf("栈为空\n");
return -1; // 返回一个特殊值表示错误
}
struct StackNode* temp = *root;
*root = (*root)->next; // 更新栈顶为下一个节点
int popped = temp->data;
free(temp); // 释放已弹出节点的内存
return popped;
}
// 获取栈顶元素
int peek(struct StackNode* root) {
if (isEmpty(root)) {
printf("栈为空\n");
return -1; // 返回一个特殊值表示错误
}
return root->data;
}
int main() {
struct StackNode* root = NULL;
push(&root, 10); // 入栈10
push(&root, 20); // 入栈20
push(&root, 30); // 入栈30
printf("栈顶元素是 %d\n", peek(root)); // 查看栈顶元素
printf("%d 出栈\n", pop(&root)); // 出栈30
printf("%d 出栈\n", pop(&root)); // 出栈20
printf("%d 出栈\n", pop(&root)); // 出栈10
// 记得释放内存
while (!isEmpty(root)) {
pop(&root);
}
return 0;
}
树
树是一种非线性的数据结构,由节点组成,其中每个节点都有零个或多个子节点。根节点没有父节点,而其他每个节点恰好有一个父节点。
二叉搜索树示例:
假设有一棵二叉搜索树包含三个节点:5 -> (3, 7)
二叉搜索树的C语言实现
#include <stdio.h>
#include <stdlib.h>
// 定义树节点结构
struct TreeNode {
int data; // 数据部分
struct TreeNode* left; // 指向左子节点的指针
struct TreeNode* right; // 指向右子节点的指针
};
// 创建新节点
struct TreeNode* createTreeNode(int data) {
struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
if (!newNode) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 插入节点到二叉搜索树
struct TreeNode* insertBST(struct TreeNode* node, int data) {
if (node == NULL) {
return createTreeNode(data); // 如果节点为空,则创建新节点
}
if (data < node->data) {
node->left = insertBST(node->left, data); // 插入左子树
} else if (data > node->data) {
node->right = insertBST(node->right, data); // 插入右子树
}
return node;
}
// 中序遍历二叉搜索树
void inorderTraversal(struct TreeNode* node) {
if (node != NULL) {
inorderTraversal(node->left); // 遍历左子树
printf("%d -> ", node->data); // 打印当前节点的数据
inorderTraversal(node->right); // 遍历右子树
}
}
int main() {
struct TreeNode* root = NULL;
root = insertBST(root, 5); // 插入节点5
insertBST(root, 3); // 插入节点3
insertBST(root, 7); // 插入节点7
printf("中序遍历结果: ");
inorderTraversal(root);
printf("NULL\n");
// 记得释放内存
// 这里为了简化,省略了具体的内存释放代码
return 0;
}
图
图是一种非线性的数据结构,由一组节点(也称为顶点)及其之间的连接(边)组成。图可以是有向的也可以是无向的。
无向图(邻接表表示法)示例:
假设有一个无向图包含五个顶点和六条边:0-1, 0-4, 1-2, 1-3, 1-4, 2-3, 3-4
邻接表表示的无向图的C语言实现
#include <stdio.h>
#include <stdlib.h>
// 定义邻接表节点
struct AdjListNode {
int dest; // 目标顶点
struct AdjListNode* next; // 指向下一条边
};
// 定义邻接表
struct AdjList {
struct AdjListNode* head; // 邻接表的头节点
};
// 定义图
struct Graph {
int V; // 顶点数量
struct AdjList* array; // 邻接表数组
};
// 创建邻接表节点
struct AdjListNode* newAdjListNode(int dest) {
struct AdjListNode* newNode = (struct AdjListNode*)malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->next = NULL;
return newNode;
}
// 创建图
struct Graph* createGraph(int V) {
struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
graph->V = V;
// 创建邻接表数组
graph->array = (struct AdjList*)malloc(V * sizeof(struct AdjList));
// 初始化每个邻接列表为空
for (int i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
// 添加边到图中
void addEdge(struct Graph* graph, int src, int dest) {
// 添加一条从src到dest的边
struct AdjListNode* newNode = newAdjListNode(dest);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
// 由于是无向图,再添加一条从dest到src的边
newNode = newAdjListNode(src);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
// 打印图
void printGraph(struct Graph* graph) {
for (int v = 0; v < graph->V; ++v) {
struct AdjListNode* pCrawl = graph->array[v].head;
printf("\n顶点 %d 的邻居:\n 头 ", v);
while (pCrawl) {
printf("-> %d", pCrawl->dest);
pCrawl = pCrawl->next;
}
printf("\n");
}
}
int main() {
// 创建一个包含5个顶点的图
int V = 5;
struct Graph* graph = createGraph(V);
addEdge(graph, 0, 1); // 添加边0-1
addEdge(graph, 0, 4); // 添加边0-4
addEdge(graph, 1, 2); // 添加边1-2
addEdge(graph, 1, 3); // 添加边1-3
addEdge(graph, 1, 4); // 添加边1-4
addEdge(graph, 2, 3); // 添加边2-3
addEdge(graph, 3, 4); // 添加边3-4
// 打印图的内容
printGraph(graph);
// 记得释放内存
for (int i = 0; i < V; ++i) {
struct AdjListNode* adjListPtr = graph->array[i].head;
while (adjListPtr) {
struct AdjListNode* tmp = adjListPtr;
adjListPtr = adjListPtr->next;
free(tmp);
}
}
free(graph->array);
free(graph);
return 0;
}