如何用C语言设计和实现数据结构
使用C语言设计和实现数据结构的核心在于:理解数据结构的本质、选择合适的数据结构以及编写高效的代码。在C语言中,设计和实现数据结构需要掌握指针、动态内存分配以及结构体等关键技术。下面我们将详细介绍如何使用C语言设计和实现常见的数据结构,包括链表、栈、队列、树和图,并提供代码示例和性能优化建议。
一、链表
链表是一种线性数据结构,其中每个元素是一个节点,节点包含数据和一个指向下一个节点的指针。链表的主要优点是插入和删除操作非常高效。
1.1 单链表
单链表是链表的一种,每个节点包含一个数据和一个指向下一个节点的指针。
#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));
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 deleteNode(struct Node head, int key) {
struct Node* temp = *head;
struct Node* prev = NULL;
if (temp != NULL && temp->data == key) {
*head = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
// 打印链表
void printList(struct Node* head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("NULLn");
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 1);
insertAtHead(&head, 2);
insertAtHead(&head, 3);
printList(head);
deleteNode(&head, 2);
printList(head);
return 0;
}
1.2 双链表
双链表是链表的另一种形式,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
// 插入节点到双链表头部
void insertAtHead(struct Node head, int data) {
struct Node* newNode = createNode(data);
newNode->next = *head;
if (*head != NULL) {
(*head)->prev = newNode;
}
*head = newNode;
}
// 删除双链表中的节点
void deleteNode(struct Node head, int key) {
struct Node* temp = *head;
while (temp != NULL && temp->data != key) {
temp = temp->next;
}
if (temp == NULL) return;
if (*head == temp) {
*head = temp->next;
}
if (temp->next != NULL) {
temp->next->prev = temp->prev;
}
if (temp->prev != NULL) {
temp->prev->next = temp->next;
}
free(temp);
}
// 打印双链表
void printList(struct Node* head) {
while (head != NULL) {
printf("%d <-> ", head->data);
head = head->next;
}
printf("NULLn");
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 1);
insertAtHead(&head, 2);
insertAtHead(&head, 3);
printList(head);
deleteNode(&head, 2);
printList(head);
return 0;
}
二、栈
栈是一种LIFO(后进先出)的数据结构,插入和删除操作仅在栈顶进行。栈的主要操作包括:压栈(push)、弹栈(pop)和查看栈顶元素(peek)。
2.1 使用数组实现栈
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000
struct Stack {
int top;
int array[MAX];
};
// 创建栈
struct Stack* createStack() {
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
stack->top = -1;
return stack;
}
// 检查栈是否为空
int isEmpty(struct Stack* stack) {
return stack->top == -1;
}
// 压栈
void push(struct Stack* stack, int data) {
if (stack->top == MAX - 1) {
printf("Stack overflown");
return;
}
stack->array[++stack->top] = data;
}
// 弹栈
int pop(struct Stack* stack) {
if (isEmpty(stack)) {
printf("Stack underflown");
return -1;
}
return stack->array[stack->top--];
}
// 查看栈顶元素
int peek(struct Stack* stack) {
if (isEmpty(stack)) {
printf("Stack is emptyn");
return -1;
}
return stack->array[stack->top];
}
int main() {
struct Stack* stack = createStack();
push(stack, 1);
push(stack, 2);
push(stack, 3);
printf("Top element is %dn", peek(stack));
printf("Popped element is %dn", pop(stack));
printf("Top element is %dn", peek(stack));
return 0;
}
2.2 使用链表实现栈
#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));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 检查栈是否为空
int isEmpty(struct Node* root) {
return !root;
}
// 压栈
void push(struct Node root, int data) {
struct Node* newNode = createNode(data);
newNode->next = *root;
*root = newNode;
printf("%d pushed to stackn", data);
}
// 弹栈
int pop(struct Node root) {
if (isEmpty(*root)) {
printf("Stack underflown");
return -1;
}
struct Node* temp = *root;
*root = (*root)->next;
int popped = temp->data;
free(temp);
return popped;
}
// 查看栈顶元素
int peek(struct Node* root) {
if (isEmpty(root)) {
printf("Stack is emptyn");
return -1;
}
return root->data;
}
int main() {
struct Node* root = NULL;
push(&root, 1);
push(&root, 2);
push(&root, 3);
printf("Top element is %dn", peek(root));
printf("Popped element is %dn", pop(&root));
printf("Top element is %dn", peek(root));
return 0;
}
三、队列
队列是一种FIFO(先进先出)的数据结构,插入操作在队尾进行,删除操作在队头进行。队列的主要操作包括:入队(enqueue)、出队(dequeue)和查看队头元素(front)。
3.1 使用数组实现队列
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000
struct Queue {
int front, rear, size;
unsigned capacity;
int* array;
};
// 创建队列
struct Queue* createQueue(unsigned capacity) {
struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
queue->capacity = capacity;
queue->front = queue->size = 0;
queue->rear = capacity - 1;
queue->array = (int*)malloc(queue->capacity * sizeof(int));
return queue;
}
// 检查队列是否已满
int isFull(struct Queue* queue) {
return queue->size == queue->capacity;
}
// 检查队列是否为空
int isEmpty(struct Queue* queue) {
return queue->size == 0;
}
// 入队
void enqueue(struct Queue* queue, int data) {
if (isFull(queue)) {
printf("Queue overflown");
return;
}
queue->rear = (queue->rear + 1) % queue->capacity;
queue->array[queue->rear] = data;
queue->size = queue->size + 1;
printf("%d enqueued to queuen", data);
}
// 出队
int dequeue(struct Queue* queue) {
if (isEmpty(queue)) {
printf("Queue underflown");
return -1;
}
int data = queue->array[queue->front];
queue->front = (queue->front + 1) % queue->capacity;
queue->size = queue->size - 1;
return data;
}
// 查看队头元素
int front(struct Queue* queue) {
if (isEmpty(queue)) {
printf("Queue is emptyn");
return -1;
}
return queue->array[queue->front];
}
int main() {
struct Queue* queue = createQueue(MAX);
enqueue(queue, 1);
enqueue(queue, 2);
enqueue(queue, 3);
printf("Front element is %dn", front(queue));
printf("Dequeued element is %dn", dequeue(queue));
printf("Front element is %dn", front(queue));
return 0;
}
3.2 使用链表实现队列
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
struct Node {
int data;
struct Node* next;
};
// 定义队列结构
struct Queue {
struct Node *front, *rear;
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 创建队列
struct Queue* createQueue() {
struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
queue->front = queue->rear = NULL;
return queue;
}
// 入队
void enqueue(struct Queue* queue, int data) {
struct Node* newNode = createNode(data);
if (queue->rear == NULL) {
queue->front = queue->rear = newNode;
printf("%d enqueued to queuen", data);
return;
}
queue->rear->next = newNode;
queue->rear = newNode;
printf("%d enqueued to queuen", data);
}
// 出队
int dequeue(struct Queue* queue) {
if (queue->front == NULL) {
printf("Queue underflown");
return -1;
}
struct Node* temp = queue->front;
queue->front = queue->front->next;
if (queue->front == NULL) {
queue->rear = NULL;
}
int data = temp->data;
free(temp);
return data;
}
// 查看队头元素
int front(struct Queue* queue) {
if (queue->front == NULL) {
printf("Queue is emptyn");
return -1;
}
return queue->front->data;
}
int main() {
struct Queue* queue = createQueue();
enqueue(queue, 1);
enqueue(queue, 2);
enqueue(queue, 3);
printf("Front element is %dn", front(queue));
printf("Dequeued element is %dn", dequeue(queue));
printf("Front element is %dn", front(queue));
return 0;
}
四、树
树是一种层次数据结构,由节点组成,其中每个节点包含数据和指向子节点的指针。树的常见类型包括二叉树、二叉搜索树、平衡树等。
4.1 二叉树
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
struct Node {
int data;
struct Node* left;
struct Node* right;
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
// 前序遍历
void preOrder(struct Node* root) {
if (root != NULL) {
printf("%d ", root->data);
preOrder(root->left);
preOrder(root->right);
}
}
// 中序遍历
void inOrder(struct Node* root) {
if (root != NULL) {
inOrder(root->left);
printf("%d ", root->data);
inOrder(root->right);
}
}
// 后序遍历
void postOrder(struct Node* root) {
if (root != NULL) {
postOrder(root->left);
postOrder(root->right);
printf("%d ", root->data);
}
}
int main() {
struct Node* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
printf("Preorder traversal: ");
preOrder(root);
printf("n");
printf("Inorder traversal: ");
inOrder(root);
printf("n");
printf("Postorder traversal: ");
postOrder(root);
printf("n");
return 0;
}
4.2 二叉搜索树
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
struct Node {
int data;
struct Node* left;
struct Node* right;
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
// 插入节点到二叉搜索树
struct Node* insert(struct Node* node, int data) {
if (node == NULL) {
return createNode(data);
}
if (data < node->data) {
node->left = insert(node->left, data);
} else if (data > node->data) {
node->right = insert(node->right, data);
}
return node;
}
// 中序遍历
void inOrder(struct Node* root) {
if (root != NULL) {
inOrder(root->left);
printf("%d ", root->data);
inOrder(root->right);
}
}
// 查找节点
struct Node* search(struct Node* root, int data) {
if (root == NULL || root->data == data) {
return root;
}
if (data < root->data) {
return search(root->left, data);
}
return search(root->right, data);
}
int main() {
struct Node* root = NULL;
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 80);
printf("Inorder traversal: ");
inOrder(root);
printf("n");
struct Node* foundNode = search(root, 40);
if (foundNode != NULL) {
printf("Node found with value %dn", foundNode->data);
} else {
printf("Node not foundn");
}
return 0;
}
五、图
图是一种非线性数据结构,由顶点和边组成。图的常见表示方法包括邻接矩阵和邻接表。
5.1 邻接矩阵表示图
#include <stdio.h>
#include <stdlib.h>
#define V 5
// 打印图的邻接矩阵
void printGraph(int graph[V][V]) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
printf("%d ", graph[i][j]);
}
printf("n");
}
}
int main() {
int graph[V][V] = {
{0, 1, 1, 0, 0},
{1, 0, 0, 1, 1},
{1, 0, 0, 1, 0},
{0, 1, 1, 0, 1},
{0, 1, 0, 1, 0}
};
printf("Adjacency matrix of the graph:n");
printGraph(graph);
return 0;
}
5.2 邻接表表示图
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
struct Node {
int dest;
struct Node* next;
};
// 定义邻接表结构
struct AdjList {
相关问答FAQs:
1. 如何在C语言中创建一个链表数据结构?
在C语言中创建链表数据结构,可以先定义一个结构体用来表示链表的节点,该结构体包含一个数据字段和一个指向下一个节点的指针字段。然后,通过动态内存分配函数malloc来创建节点,并使用指针来连接节点,形成链表。
2. 如何在C语言中实现栈数据结构?
要在C语言中实现栈数据结构,可以使用数组或链表来存储栈元素。使用数组时,可以定义一个固定大小的数组,同时维护一个指向栈顶的指针,通过修改指针的位置来实现入栈和出栈操作。使用链表时,可以定义一个结构体表示栈节点,该结构体包含一个数据字段和一个指向下一个节点的指针字段,通过动态内存分配函数malloc来创建节点,并使用指针来连接节点,形成链表。
3. 如何在C语言中实现队列数据结构?
在C语言中实现队列数据结构,可以使用数组或链表来存储队列元素。使用数组时,可以定义一个固定大小的数组,同时维护一个指向队列头和尾的指针,通过修改指针的位置来实现入队和出队操作。使用链表时,可以定义一个结构体表示队列节点,该结构体包含一个数据字段和一个指向下一个节点的指针字段,通过动态内存分配函数malloc来创建节点,并使用指针来连接节点,形成链表。
原创文章,作者:Edit1,如若转载,请注明出处:https://docs.pingcode.com/baike/1096278