目录
一个线性表是由零个或多个具有相同类型的结点组成的有序集合。
按照线性表结点间的逻辑顺序依次将它们存储于一组地址连续的存储单元中的存储方式被称为线性表的顺序存储方式。按顺序存储方式存储的线性表具有顺序存储结构,一般称之为顺序表。换言之,在程序中采用定长的一维数组,按照顺序存储方式存储的线性表,被称为顺序表。

顺序表的优点是存取速度快。但是,无论是插入一个结点,还是删除一个结点,都需要调整一批结点的地址。要克服该缺点,就必须给出一种不同于顺序存储的存储方式。用链接存储方式存储的线性表被称为链表,可以克服上述缺点。
链表中的结点用存储单元(若干个连续字节)来存放,存储单元之间既可以是(存储空间上)连续的,也可以是不连续的,甚至可以零散地分布在存储空间中的任何位置。换言之,链表中结点的逻辑次序和物理次序之间并无必然联系。最重要的是,链表可以在不移动结点位置的前提下根据需要随时添加删除结点,动态调整。

从单链表的一个结点出发,只能访问到链接在它后面的结点,而无法访问位于它前面的结点,这对一些实际应用很不方便。解决的办法是把链接结构“循环化”,即把表尾结点的next域存放指向哨位结点的指针,而不是存放空指针NULL,这样的单链表被称为循环链表。循环链表使用户可以从链表的任何位置开始,访问链表中的任意结点。

- typedef struct Node {
- int data; // 数据域
- struct Node *next; // 指针域
- } Node;
包含一个整型数据域 data 和一个指向下一个节点的指针域 next。
- Node* createNode(int data) {
- Node* newNode = (Node*)malloc(sizeof(Node));
- newNode->data = data;
- newNode->next = NULL;
- return newNode;
- }
malloc 分配了节点的内存空间;data 字段,并将 next 字段设置为 NULL。- void insert(Node** head, int data) {
- Node* newNode = createNode(data);
-
- if (*head == NULL) {
- *head = newNode;
- (*head)->next = *head; // 将尾节点指向头节点,形成循环
- } else {
- Node* temp = *head;
- while (temp->next != *head) {
- temp = temp->next;
- }
- temp->next = newNode;
- newNode->next = *head;
- }
- }
createNode 函数创建一个新节点,并将新节点的指针保存在 newNode 中。head 指向新节点,并将新节点的指针域 next 设置为指向自己,这样形成一个只有一个节点的循环链表。

next 指向新节点,新节点的指针域 next 指向头节点,完成节点的插入操作。- void deleteNode(Node** head, int data) {
- if (*head == NULL) {
- return;
- }
-
- Node* currNode = *head;
- Node* prevNode = NULL;
-
- while (currNode->next != *head) {
- if (currNode->data == data) {
- if (prevNode == NULL) {
- Node* lastNode = *head;
- while (lastNode->next != *head) {
- lastNode = lastNode->next;
- }
- *head = currNode->next;
- lastNode->next = *head;
- } else {
- prevNode->next = currNode->next;
- }
- free(currNode);
- return;
- }
-
- prevNode = currNode;
- currNode = currNode->next;
- }
-
- if (currNode->data == data) {
- if (prevNode == NULL) {
- *head = NULL;
- } else {
- prevNode->next = *head;
- }
- free(currNode);
- }
- }
currNode 和 prevNode
currNode 指向当前节点,初始时指向头节点prevNode指向前一个节点,初始为 NULL*head 的值为删除节点的下一个节点,最后释放删除节点的内存。next 指向删除节点的下一个节点,然后释放删除节点的内存。- Node* search(Node* head, int data) {
- if (head == NULL) {
- return NULL;
- }
-
- Node* currNode = head;
-
- while (currNode->next != head) {
- if (currNode->data == data) {
- return currNode;
- }
- currNode = currNode->next;
- }
-
- if (currNode->data == data) {
- return currNode;
- }
-
- return NULL;
- }
currNode,初始时指向头节点。- void modify(Node* head, int oldData, int newData) {
- Node* nodeToModify = search(head, oldData);
-
- if (nodeToModify != NULL) {
- nodeToModify->data = newData;
- }
- }
search 函数查找指定值的节点,并将返回的节点指针保存在 nodeToModify 中data 更新为 newData。- void printList(Node* head) {
- if (head == NULL) {
- printf("循环链表为空\n");
- return;
- }
-
- Node* currNode = head;
-
- do {
- printf("%d ", currNode->data);
- currNode = currNode->next;
- } while (currNode != head);
-
- printf("\n");
- }
currNode,初始时指向头节点。- void freeList(Node** head) {
- if (*head == NULL) {
- return;
- }
-
- Node* currNode = *head;
- Node* nextNode = NULL;
-
- while (currNode->next != *head) {
- nextNode = currNode->next;
- free(currNode);
- currNode = nextNode;
- }
-
- free(currNode);
- *head = NULL;
- }
currNode 和 nextNode
currNode 指向当前节点,初始时指向头节点nextNode指向下一个节点,初始为 NULLnextNode 指向 currNode 的下一个节点,释放 currNode 指向的节点的内存,然后将 currNode 更新为 nextNode。重复以上步骤,直到遍历完整个链表,并最后释放头节点的内存。- int main() {
- Node* head = NULL;
-
- // 在循环链表中插入节点
- insert(&head, 10);
- insert(&head, 20);
- insert(&head, 30);
- insert(&head, 40);
-
- // 打印循环链表
- printf("循环链表: ");
- printList(head);
-
- // 删除循环链表中的节点
- deleteNode(&head, 20);
-
- // 打印删除节点后的循环链表
- printf("删除节点后的循环链表: ");
- printList(head);
-
- // 在循环链表中查找节点
- Node* searchResult = search(head, 30);
- if (searchResult != NULL) {
- printf("找到节点 %d\n", searchResult->data);
- } else {
- printf("未找到节点\n");
- }
-
- // 修改循环链表中的节点值
- modify(head, 30, 50);
-
- // 打印修改节点值后的循环链表
- printf("修改节点值后的循环链表: ");
- printList(head);
-
- // 释放循环链表内存空间
- freeList(&head);
-
- return 0;
- }
head,初始时为 NULL。insert 函数,在循环链表中插入了四个节点,其数据分别为 10、20、30 和 40。deleteNode 函数删除了值为 20 的节点,并再次调用 printList 函数打印删除节点后的循环链表。search 函数查找值为 30 的节点,并根据返回结果打印相应的信息。modify 函数修改值为 30 的节点的数据为 50,freeList 函数释放循环链表占用的内存空间。
- #include
- #include
-
- // 定义循环链表节点结构体
- typedef struct Node {
- int data; // 数据域
- struct Node *next; // 指针域
- } Node;
-
- // 创建新节点
- Node* createNode(int data) {
- Node* newNode = (Node*)malloc(sizeof(Node));
- newNode->data = data;
- newNode->next = NULL;
- return newNode;
- }
-
- // 在循环链表末尾插入节点
- void insert(Node** head, int data) {
- Node* newNode = createNode(data);
-
- if (*head == NULL) {
- *head = newNode;
- (*head)->next = *head; // 将尾节点指向头节点,形成循环
- } else {
- Node* temp = *head;
- while (temp->next != *head) {
- temp = temp->next;
- }
- temp->next = newNode;
- newNode->next = *head;
- }
- }
-
- // 删除循环链表中指定值的节点
- void deleteNode(Node** head, int data) {
- if (*head == NULL) {
- return;
- }
-
- Node* currNode = *head;
- Node* prevNode = NULL;
-
- while (currNode->next != *head) {
- if (currNode->data == data) {
- if (prevNode == NULL) {
- Node* lastNode = *head;
- while (lastNode->next != *head) {
- lastNode = lastNode->next;
- }
- *head = currNode->next;
- lastNode->next = *head;
- } else {
- prevNode->next = currNode->next;
- }
- free(currNode);
- return;
- }
-
- prevNode = currNode;
- currNode = currNode->next;
- }
-
- if (currNode->data == data) {
- if (prevNode == NULL) {
- *head = NULL;
- } else {
- prevNode->next = *head;
- }
- free(currNode);
- }
- }
-
- // 在循环链表中查找指定值的节点
- Node* search(Node* head, int data) {
- if (head == NULL) {
- return NULL;
- }
-
- Node* currNode = head;
-
- while (currNode->next != head) {
- if (currNode->data == data) {
- return currNode;
- }
- currNode = currNode->next;
- }
-
- if (currNode->data == data) {
- return currNode;
- }
-
- return NULL;
- }
-
- // 修改循环链表中指定节点的值
- void modify(Node* head, int oldData, int newData) {
- Node* nodeToModify = search(head, oldData);
-
- if (nodeToModify != NULL) {
- nodeToModify->data = newData;
- }
- }
-
- // 打印循环链表
- void printList(Node* head) {
- if (head == NULL) {
- printf("循环链表为空\n");
- return;
- }
-
- Node* currNode = head;
-
- do {
- printf("%d ", currNode->data);
- currNode = currNode->next;
- } while (currNode != head);
-
- printf("\n");
- }
-
- // 释放循环链表内存空间
- void freeList(Node** head) {
- if (*head == NULL) {
- return;
- }
-
- Node* currNode = *head;
- Node* nextNode = NULL;
-
- while (currNode->next != *head) {
- nextNode = currNode->next;
- free(currNode);
- currNode = nextNode;
- }
-
- free(currNode);
- *head = NULL;
- }
-
- int main() {
- Node* head = NULL;
-
- // 在循环链表中插入节点
- insert(&head, 10);
- insert(&head, 20);
- insert(&head, 30);
- insert(&head, 40);
-
- // 打印循环链表
- printf("循环链表: ");
- printList(head);
-
- // 删除循环链表中的节点
- deleteNode(&head, 20);
-
- // 打印删除节点后的循环链表
- printf("删除节点后的循环链表: ");
- printList(head);
-
- // 在循环链表中查找节点
- Node* searchResult = search(head, 30);
- if (searchResult != NULL) {
- printf("找到节点 %d\n", searchResult->data);
- } else {
- printf("未找到节点\n");
- }
-
- // 修改循环链表中的节点值
- modify(head, 30, 50);
-
- // 打印修改节点值后的循环链表
- printf("修改节点值后的循环链表: ");
- printList(head);
-
- // 释放循环链表内存空间
- freeList(&head);
-
- return 0;
- }