简介
数据结构是计算机科学中的一个重要概念,指的是数据在计算机中的组织和存储方式。在C语言中,数据结构是构建高效算法和应用程序的基础。本博客将介绍几种常见的数据结构,包括数组、链表、栈、队列、树和哈希表,并提供相应的代码示例。
内容
1. 数组 (Array)
定义与特点:
- 数组是一种线性数据结构,用于存储相同类型的元素。
- 在内存中是连续存储的,每个元素可以通过索引访问。
- 数组的大小在创建时固定,无法动态改变。
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};// 访问数组元素
printf("Element at index 0: %d\n", arr[0]);// 修改数组元素
arr[2] = 10;// 遍历数组
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");return 0;
}
基本操作:
访问:通过索引访问数组元素,时间复杂度为O(1)。
插入和删除:在指定位置插入或删除元素时,需要移动后续元素,时间复杂度为O(n)。
2. 链表 (Linked List)
定义与特点:
链表是一种动态数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。
内存中的节点可以不连续,通过指针链接节点。
可以是单链表、双链表或循环链表。
示例代码:单链表
#include <stdio.h>
#include <stdlib.h>typedef struct Node {
int data;
struct Node* next;
} Node;void printList(Node* n) {
while (n != NULL) {
printf("%d ", n->data);
n = n->next;
}
printf("\n");
}int main() {
Node* head = NULL;
Node* second = NULL;
Node* third = NULL;// 分配节点
head = (Node*)malloc(sizeof(Node));
second = (Node*)malloc(sizeof(Node));
third = (Node*)malloc(sizeof(Node));head->data = 1;
head->next = second;second->data = 2;
second->next = third;third->data = 3;
third->next = NULL;// 打印链表
printList(head);return 0;
}
基本操作:
插入:在任意位置插入节点,时间复杂度为O(1)。
删除:删除任意节点,时间复杂度为O(1)(如果有指向被删除节点的指针)或O(n)(需要遍历找到节点)。
查找:遍历链表查找特定元素,时间复杂度为O(n)。
3. 栈 (Stack)
定义与特点:
栈是一种后进先出(LIFO)的数据结构,只能在一端进行插入和删除操作,称为栈顶。
主要操作包括压栈(push)和弹栈(pop)。
示例代码:
#include <stdio.h>
#define MAX 5typedef struct {
int top;
int items[MAX];
} Stack;void push(Stack* s, int item) {
if (s->top == MAX - 1) {
printf("Stack overflow\n");
} else {
s->items[++(s->top)] = item;
}
}int pop(Stack* s) {
if (s->top == -1) {
printf("Stack underflow\n");
return -1;
} else {
return s->items[(s->top)--];
}
}int main() {
Stack s;
s.top = -1;push(&s, 1);
push(&s, 2);
push(&s, 3);printf("Popped item: %d\n", pop(&s));
printf("Popped item: %d\n", pop(&s));return 0;
}
基本操作:
push:将元素压入栈顶,时间复杂度为O(1)。
pop:从栈顶弹出元素,时间复杂度为O(1)。
4. 队列 (Queue)
定义与特点:
队列是一种先进先出(FIFO)的数据结构,插入操作在队尾进行,删除操作在队首进行。
主要操作包括入队(enqueue)和出队(dequeue)。
示例代码:
#include <stdio.h>
#define MAX 5typedef struct {
int front, rear, size;
int items[MAX];
} Queue;void enqueue(Queue* q, int item) {
if (q->size == MAX) {
printf("Queue overflow\n");
} else {
q->rear = (q->rear + 1) % MAX;
q->items[q->rear] = item;
q->size++;
}
}int dequeue(Queue* q) {
if (q->size == 0) {
printf("Queue underflow\n");
return -1;
} else {
int item = q->items[q->front];
q->front = (q->front + 1) % MAX;
q->size--;
return item;
}
}int main() {
Queue q;
q.front = 0;
q.rear = -1;
q.size = 0;enqueue(&q, 1);
enqueue(&q, 2);
enqueue(&q, 3);printf("Dequeued item: %d\n", dequeue(&q));
printf("Dequeued item: %d\n", dequeue(&q));return 0;
}
基本操作:
enqueue:将元素插入队尾,时间复杂度为O(1)。
dequeue:从队首删除元素,时间复杂度为O(1)。
5. 树 (Tree)
定义与特点:
树是一种非线性数据结构,由节点组成,每个节点可以有零个或多个子节点。
最常见的树结构是二叉树,每个节点最多有两个子节点:左子节点和右子节点。
示例代码:二叉树的中序遍历
#include <stdio.h>
#include <stdlib.h>typedef struct Node {
int data;
struct Node* left;
struct Node* right;
} Node;Node* newNode(int data) {
Node* node = (Node*)malloc(sizeof(Node));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}void inorderTraversal(Node* root) {
if (root != NULL) {
inorderTraversal(root->left);
printf("%d ", root->data);
inorderTraversal(root->right);
}
}int main() {
Node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);printf("Inorder traversal: ");
inorderTraversal(root);return 0;
}
基本操作:
插入:将新节点插入到适当位置。
删除:从树中移除节点。
查找:查找特定值的节点。
遍历:遍历树中的所有节点,包括前序、中序和后序遍历。
结语
以上是关于C语言中常见数据结构的详细讲解及示例代码。理解这些数据结构的特点、基本操作以及适用场景对于编写高效的程序至关重要。