定制魏:QTWZPW,获取更多源码等
目录
基础知识
在C语言中,链表是一种常见的数据结构,用于存储一系列元素。链表由一系列节点组成,每个节点包含数据以及一个指向下一个节点的指针。以下是关于C语言链表的基础知识:
节点结构体定义:链表中的每个节点通常通过结构体来表示,结构体包含数据成员和指向下一个节点的指针成员。例如:
typedef struct Node {
int data;
struct Node* next;
} Node;
链表的概念:链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。与数组不同,链表的内存分配是动态的,节点可以在内存中的任何地方分配,通过指针进行连接。单向链表:最基本的链表形式是单向链表,其中每个节点包含数据和指向下一个节点的指针。单向链表只能从头节点开始沿着指针方向遍历,无法反向遍历。
双向链表:双向链表的节点除了包含数据和指向下一个节点的指针外,还包含指向前一个节点的指针。这样的设计使得双向链表可以双向遍历,灵活性更高。
循环链表:循环链表是一种特殊的链表,最后一个节点的指针指向第一个节点,形成一个闭环。循环链表可以很方便地实现循环操作。
链表的优缺点:链表的优点包括插入和删除节点方便快捷,不需要提前知道存储空间大小。缺点包括访问元素时需要遍历,无法像数组那样通过索引直接访问元素,而且消耗一定的额外存储空间来存储指针。
单向链表实现
//单向链表实现
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构体
//定义了一个名为Node的结构体,包含一个整型数据成员data和一个指向下一个Node结构体的指针next。
typedef struct Node { // 定义名为Node的结构体
int data; // 整型数据成员
struct Node* next; // 指向下一个Node结构体的指针
} Node;
// 创建新节点
//定义了一个函数createNode,用于创建一个新的链表节点,参数data表示新节点的数据值,函数返回指向新节点的指针。
Node* createNode(int data) { // 创建新节点的函数,传入一个整型参数data
Node* newNode = (Node*)malloc(sizeof(Node)); // 使用malloc函数分配内存空间
newNode->data = data; // 将data赋值给新节点的data成员
newNode->next = NULL; // 将新节点的next指针设为NULL
return newNode; // 返回新创建的节点指针
}
// 插入节点到链表尾部
//定义了一个函数insertNode,用于向链表尾部插入一个新节点,参数head是指向链表头指针的指针,参数data是新节点的数据值。
void insertNode(Node** head, int data) { // 向链表尾部插入节点的函数,传入指向头指针的指针和整型参数data
Node* newNode = createNode(data); // 调用createNode函数创建新节点
if (*head == NULL) { // 如果链表为空
*head = newNode; // 将头指针指向新节点
} else { // 如果链表不为空
Node* current = *head; // 创建临时指针指向头指针
while (current->next != NULL) { // 遍历链表直到最后一个节点
current = current->next; // 移动当前指针到下一个节点
}
current->next = newNode; // 将新节点连接到当前节点的next指针
}
}
// 冒泡排序函数
//用于对链表进行冒泡排序,参数head是指向链表头节点的指针。
void bubbleSort(Node* head) { // 冒泡排序函数,传入链表头指针
int swapped, temp; // 定义交换标志和临时变量
Node* ptr1; // 定义指向节点的指针
Node* lptr = NULL; // 定义最后交换位置的节点指针
// 如果链表为空或只有一个节点,则无需排序
if (head == NULL)
return;
do {
swapped = 0; // 重置交换标志
ptr1 = head; // 将指针指向链表头部
while (ptr1->next != lptr) { // 遍历链表直到最后交换位置的前一个节点
if (ptr1->data > ptr1->next->data) { // 如果当前节点的值大于下一个节点的值
temp = ptr1->data; // 交换两个节点的值
ptr1->data = ptr1->next->data;
ptr1->next->data = temp;
swapped = 1; // 设置交换标志
}
ptr1 = ptr1->next; // 移动当前指针到下一个节点
}
lptr = ptr1; // 更新最后交换位置的节点指针
} while (swapped); // 如果发生过交换则继续循环
}
// 打印链表
//用于打印链表的所有节点数据值,参数node是指向链表头节点的指针。
void printList(Node* node) { // 打印链表的函数,传入链表头指针
while (node != NULL) { // 遍历链表
printf("%d ", node->data); // 打印当前节点的值
node = node->next; // 移动到下一个节点
}
printf("\n"); // 打印换行
}
代码储存初始链表
//主函数main,首先创建了一个头指针head并初始化为空,然后调用insertNode函数向链表插入了一些节点,
//接着打印原始链表,调用bubbleSort函数对链表进行排序,最后打印排序后的链表。
int main() {
Node* head = NULL; // 定义头指针并初始化为空
// 插入节点到链表
insertNode(&head, 5); // 插入数值为5的节点
insertNode(&head, 2); // 插入数值为2的节点
insertNode(&head, 8); // 插入数值为8的节点
insertNode(&head, 1); // 插入数值为1的节点
insertNode(&head, 6); // 插入数值为6的节点
printf("原始链表:\n");
printList(head); // 打印原始链表
// 调用冒泡排序函数进行排序
bubbleSort(head); // 对链表进行排序
printf("排序后的链表:\n");
printList(head); // 打印排序后的链表
return 0; // 返回0表示程序成功执行
}
自己输入初始链表
//在主函数中,首先初始化一个头指针head为空,并定义变量data和inputFlag。
//使用do-while循环,循环提示用户输入节点的数值,将数值插入到链表中,然后询问用户是否继续添加节点,根据用户输入的选择决定是否继续循环。
int main() {
Node* head = NULL; // 头指针初始化为空
int data;
char inputFlag;
do {
printf("请输入节点的数值:");
scanf("%d", &data);
insertNode(&head, data);
printf("是否继续添加节点?(y/n): ");
scanf(" %c", &inputFlag);
} while (inputFlag == 'y');
printf("原始链表:\n");
printList(head); // 输出原始链表
// 调用冒泡排序函数进行排序
bubbleSort(head);
printf("排序后的链表:\n");
printList(head); // 输出排序后的链表
return 0; // 返回值0,表示程序正常结束
}
双向链表实现
#include <stdio.h>
#include <stdlib.h>
// 定义双向链表节点结构体
typedef struct Node { // 定义名为Node的结构体
int data; // 整型数据成员
struct Node* prev; // 指向前一个Node结构体的指针
struct Node* next; // 指向下一个Node结构体的指针
} Node;
// 创建新节点
Node* createNode(int data) { // 创建新节点的函数,传入一个整型参数data
Node* newNode = (Node*)malloc(sizeof(Node)); // 使用malloc函数分配内存空间
newNode->data = data; // 将data赋值给新节点的data成员
newNode->prev = NULL; // 将新节点的prev指针设为NULL
newNode->next = NULL; // 将新节点的next指针设为NULL
return newNode; // 返回新创建的节点指针
}
// 插入节点到双向链表尾部
void insertNode(Node** head, int data) { // 向双向链表尾部插入节点的函数,传入指向头指针的指针和整型参数data
Node* newNode = createNode(data); // 调用createNode函数创建新节点
if (*head == NULL) { // 如果链表为空
*head = newNode; // 将头指针指向新节点
} else { // 如果链表不为空
Node* current = *head; // 创建临时指针指向头指针
while (current->next != NULL) { // 遍历链表直到最后一个节点
current = current->next; // 移动当前指针到下一个节点
}
current->next = newNode; // 将新节点连接到当前节点的next指针
newNode->prev = current; // 将当前节点连接到新节点的prev指针
}
}
// 冒泡排序函数
void bubbleSort(Node* head) { // 冒泡排序函数,传入双向链表头指针
int swapped, temp; // 定义交换标志和临时变量
Node* ptr1; // 定义指向节点的指针
Node* lptr = NULL; // 定义最后交换位置的节点指针
// 如果链表为空或只有一个节点,则无需排序
if (head == NULL)
return;
do {
swapped = 0; // 重置交换标志
ptr1 = head; // 将指针指向链表头部
while (ptr1->next != lptr) { // 遍历链表直到最后交换位置的前一个节点
if (ptr1->data > ptr1->next->data) { // 如果当前节点的值大于下一个节点的值
temp = ptr1->data; // 交换两个节点的值
ptr1->data = ptr1->next->data;
ptr1->next->data = temp;
swapped = 1; // 设置交换标志
}
ptr1 = ptr1->next; // 移动当前指针到下一个节点
}
lptr = ptr1; // 更新最后交换位置的节点指针
} while (swapped); // 如果发生过交换则继续循环
}
// 打印双向链表
void printList(Node* node) { // 打印双向链表的函数,传入链表头指针
while (node != NULL) { // 遍历链表
printf("%d ", node->data); // 打印当前节点的值
node = node->next; // 移动到下一个节点
}
printf("\n"); // 打印换行
}
int main() {
Node* head = NULL; // 定义头指针并初始化为空
// 插入节点到双向链表
insertNode(&head, 5); // 插入数值为5的节点
insertNode(&head, 2); // 插入数值为2的节点
insertNode(&head, 8); // 插入数值为8的节点
insertNode(&head, 1); // 插入数值为1的节点
insertNode(&head, 6); // 插入数值为6的节点
printf("原始双向链表:\n");
printList(head); // 打印原始双向链表
// 调用冒泡排序函数进行排序
bubbleSort(head); // 对双向链表进行排序
printf("排序后的双向链表:\n");
printList(head); // 打印排序后的双向链表
return 0; // 返回0表示程序成功执行
}