一、链表的概念
链表是由若干个结点组成,且结点在内存中的存储位置通常是不连续的。除此之外,链表的两个结点之间一般通过一个指针来从一个结点指向另一个结点。定义如下:
1 #define typename int 2 // 链表结构 3 struct node { 4 typename data; 5 node* next; 6 };
二、使用 malloc 函数为链表结点分配内存空间
1. malloc 函数
malloc 函数是 C 语言中 stdlib.h 头文件下用于申请动态内存的函数,其返回类型是申请同变量变型的指针,其基本用法如下:
typename* p = (typename*)malloc(sizeof(typename));
那么创建一个链表结点的代码如下:
node* p = (node*)malloc(sizeof(node));
2. free 函数
free 函数对应 malloc 函数,同样是在 stdlib.h 头文件下。其使用方法如下:
free(p);
三、链表的基本操作
1. 创建链表
根据数组创建链表,代码如下:
1 /* 2 链表处理 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <math.h> 8 #include <stdlib.h> 9 #include <time.h> 10 #include <stdbool.h> 11 12 #define typename int 13 // 链表结构 14 typedef struct _node { 15 typename data; 16 struct _node* next; 17 } node; 18 19 /* 20 // 分配内存 21 typename* p = (typename*)malloc(sizeof(typename)); 22 node* p = (node*)malloc(sizeof(node)); 23 free(p); 24 */ 25 26 // 创建链表 27 node* create(int Array[], int n) { 28 node *p, *pre, *head; // 当前结点,前置节点,头结点 29 head = (node*)malloc(sizeof(node)); // 创建头结点 30 head->next = NULL; 31 pre = head; // 记录 pre 为 head 32 int i; 33 for(i=0; i<n; ++i) { 34 p = (node*)malloc(sizeof(node)); // 新建结点 35 p->data = Array[i]; // 赋值 36 p->next = NULL; 37 pre->next = p; // 尾插法 38 pre = p; 39 } 40 return head; 41 } 42 43 int main() { 44 int Array[5] = {5, 3, 6, 1, 2}; 45 node* L = create(Array, 5); 46 L = L->next; // 第一个结点 47 while(L != NULL) { // 顺序输出 48 printf("%d ", L->data); 49 L = L->next; 50 } 51 52 return 0; 53 }
2. 查找元素
只需从第一个结点开始,不断判断当前结点的数据域是否等于 x,如果等于,那么就给计数器 count 加 1。这样当到达链表结尾时,count 的值就是链表中元素 x 的个数。代码如下:
1 // 在以 head 为头结点的链表上计数元素 x 的个数 2 int search(node* head, int x) { 3 int count = 0; // 计数 4 node* p = head->next; // 从第一个结点开始 5 while(p != NULL) { 6 if(p->data == x) { // 当前结点数据域为 x 7 count ++; 8 } 9 p = p->next; // 移动到下一个结点 10 } 11 return count; 12 }
3. 插入元素
在指定元素插入元素,代码如下:
1 // 将 x 插入以 head 为头结点的链表的第 pos 个位置上 2 void insert(node* head, int pos, int x) { 3 node* p = head; 4 int i; 5 for(i=0; i<pos-1; ++i) { // 指针移到第 pos-1 个位置 6 p = p->next; 7 } 8 node* q = (node*)malloc(sizeof(node)); // 新结点 9 q->data = x; 10 q->next = p->next; // 插入新结点 11 p->next = q; 12 }
4. 删除元素
对链表来说,删除元素是指删除链表上所有值为给定的数 x 的结点。代码如下:
1 // 删除以 head 为头结点的链表中所有数据域为 x 的结点 2 void del(node* head, int x) { 3 node* p = head->next; // 从第一个结点开始遍历 4 node* pre = head; // pre 为 p 的前驱结点 5 while(p != NULL) { 6 if(p->data == x) { // 当前结点数据域为 x 7 pre->next = p->next; // 删除当前结点 8 free(p); 9 p = pre->next; // 更新当前结点 10 } else { // 当前结点数据域不是 x 11 pre = p; // p pre 同时后移 12 p = p->next; 13 } 14 } 15 }
完整 C 代码如下:
1 /* 2 链表处理 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <math.h> 8 #include <stdlib.h> 9 #include <time.h> 10 #include <stdbool.h> 11 12 #define typename int 13 // 链表结构 14 typedef struct _node { 15 typename data; 16 struct _node* next; 17 } node; 18 19 /* 20 // 分配内存 21 typename* p = (typename*)malloc(sizeof(typename)); 22 node* p = (node*)malloc(sizeof(node)); 23 free(p); 24 */ 25 26 // 创建链表 27 node* create(int Array[], int n) { 28 node *p, *pre, *head; // 当前结点,前置节点,头结点 29 head = (node*)malloc(sizeof(node)); // 创建头结点 30 head->next = NULL; 31 pre = head; // 记录 pre 为 head 32 int i; 33 for(i=0; i<n; ++i) { 34 p = (node*)malloc(sizeof(node)); // 新建结点 35 p->data = Array[i]; // 赋值 36 p->next = NULL; 37 pre->next = p; // 尾插法 38 pre = p; 39 } 40 return head; 41 } 42 43 // 在以 head 为头结点的链表上计数元素 x 的个数 44 int search(node* head, int x) { 45 int count = 0; // 计数 46 node* p = head->next; // 从第一个结点开始 47 while(p != NULL) { 48 if(p->data == x) { // 当前结点数据域为 x 49 count ++; 50 } 51 p = p->next; // 移动到下一个结点 52 } 53 return count; 54 } 55 56 // 将 x 插入以 head 为头结点的链表的第 pos 个位置上 57 void insert(node* head, int pos, int x) { 58 node* p = head; 59 int i; 60 for(i=0; i<pos-1; ++i) { // 指针移到第 pos-1 个位置 61 p = p->next; 62 } 63 node* q = (node*)malloc(sizeof(node)); // 新结点 64 q->data = x; 65 q->next = p->next; // 插入新结点 66 p->next = q; 67 } 68 69 // 删除以 head 为头结点的链表中所有数据域为 x 的结点 70 void del(node* head, int x) { 71 node* p = head->next; // 从第一个结点开始遍历 72 node* pre = head; // pre 为 p 的前驱结点 73 while(p != NULL) { 74 if(p->data == x) { // 当前结点数据域为 x 75 pre->next = p->next; // 删除当前结点 76 free(p); 77 p = pre->next; // 更新当前结点 78 } else { // 当前结点数据域不是 x 79 pre = p; // p pre 同时后移 80 p = p->next; 81 } 82 } 83 } 84 85 // 顺序输出以 head 为头结点的链表 86 void print(node* head) { 87 node* p = head->next; // 第一个结点 88 while(p != NULL) { // 顺序输出 89 printf("%d ", p->data); 90 p = p->next; 91 } 92 printf("\n"); 93 } 94 95 int main() { 96 int Array[10] = {5, 3, 6, 5, 4, 3, 5, 5, 1, 2}; 97 node* L = create(Array, 10); 98 print(L); 99 insert(L, 3, 5); // 在第 3 位插入 5 100 print(L); 101 del(L, 3); // 删除数据域为 3 的结点 102 print(L); 103 printf("count = %d\n", search(L, 5)); 104 105 return 0; 106 }