农业网站怎么做郑州seo顾问培训
news/
2025/10/9 2:18:02/
文章来源:
农业网站怎么做,郑州seo顾问培训,天津建设网投标网站,html5手机商城网站模板链表
链表#xff08;Linked List#xff09;是一种常见的数据结构#xff0c;用于存储一系列具有相同类型的元素。链表由节点#xff08;Node#xff09;组成#xff0c;每个节点包含两部分#xff1a;数据域#xff08;存储元素值#xff09;和指针域#xff08;指…链表
链表Linked List是一种常见的数据结构用于存储一系列具有相同类型的元素。链表由节点Node组成每个节点包含两部分数据域存储元素值和指针域指向下一个节点。通过节点之间的指针连接形成一个链式结构。
链表可以分为单向链表和双向链表两种类型。在单向链表中每个节点只有一个指针指向下一个节点而在双向链表中每个节点有两个指针分别指向前一个节点和后一个节点。
链表的优点是插入和删除操作的时间复杂度为O(1)而不受数据规模的影响。但是访问链表中的特定元素需要从头开始遍历链表时间复杂度为O(n)其中n是链表的长度。
链表在实际应用中有广泛的用途比如实现栈、队列、哈希表等数据结构以及解决一些特定的问题如反转链表、合并有序链表等。
需要注意的是在使用链表时我们需要额外的空间来存储指针因此链表对内存的利用率较低。同时在频繁插入和删除操作较多而对访问操作要求不高的情况下链表是一个较为合适的选择。 单链表Singly Linked List是一种常见的链表结构由一系列节点按顺序连接而成。每个节点包含两个部分数据域存储元素值和指针域指向下一个节点。最后一个节点的指针域指向空NULL。
以下是单链表的基本结构
Node:- 数据域Data: 存储元素值- 指针域Next: 指向下一个节点LinkedList:- 头指针Head: 指向链表的第一个节点单链表的头指针Head用于标识链表的起始位置。通过头指针可以遍历整个链表或者在链表中插入、删除节点。
单链表的特点是每个节点只有一个指针域指向下一个节点最后一个节点的指针域为空。这意味着在单链表中只能从前往后遍历无法直接访问前一个节点因此对于某些操作比如在给定节点之前插入一个新节点需要额外的操作来处理指针。
需要注意的是单链表中的节点可以动态地分配内存这意味着可以根据需求灵活地扩展或缩小链表的长度。
下面是一个示例单链表的结构
Head - Node1 - Node2 - Node3 - ... - NULL其中Head是头指针Node1、Node2、Node3等为节点箭头表示指针域的指向关系NULL表示链表的结束。
单链表的操作包括插入节点、删除节点、查找节点、遍历链表等这些操作可以根据具体需求进行实现。 题1.若线性表采用链式存储则表中各元素的存储地址()。 A.必须是连续的 B.部分地址是连续的 C.一定是不连续的 D.不一定是连续的 答案D 题2.单链表中增加一个头结点的目的是为了()。 A.使单链表至少有一个结点 B.标识表结点中首结点的位置 C.方便运算的实现 D.说明单链表是线性表的链式存储 答案C
题1的答案是D. 不一定是连续的。
如果线性表采用链式存储方式表中各元素的存储地址不需要连续。链式存储通过节点之间的指针连接每个节点可以分配在内存的任意位置。节点的指针域存储着下一个节点的地址通过指针的链接实现了元素之间的逻辑关系。
题2的答案是C. 方便运算的实现。
增加一个头结点的目的是为了方便对单链表进行操作和实现一些常用的操作如插入、删除、查找等。头结点不存储具体的数据它的存在主要是为了简化操作使得对链表的操作更加统一和方便。头结点可以作为操作的起点避免了对空链表的特殊处理提高了代码的可读性和可维护性。
引入头结点后可以带来两个优点 ①由于第一个数据结点的位置被存放在头结点的指针域中所以在链表的第一个位置上的操作和在表的其他位置上的操作一致无需进行特殊处理。 ②无论链表是否为空其头指针都指向头结点的非空指针空表中头结点的指针域为空)。
单链表的实现
以下是单链表的详细实现示例使用C语言
定义节点结构Node
struct Node {int data;struct Node *next;
};定义链表结构LinkedList
struct LinkedList {struct Node *head;
};实现插入操作
void insert(struct LinkedList *list, int data) {struct Node *new_node (struct Node *)malloc(sizeof(struct Node)); // 创建新节点new_node-data data;new_node-next NULL;if (list-head NULL) { // 如果链表为空将新节点设为头节点list-head new_node;} else {struct Node *current list-head;while (current-next ! NULL) { // 遍历到最后一个节点current current-next;}current-next new_node; // 将新节点插入在最后一个节点之后}
}实现删除操作
void delete(struct LinkedList *list, int target) {if (list-head NULL) { // 如果链表为空无法删除return;}if (list-head-data target) { // 如果要删除的节点是头节点struct Node *temp list-head;list-head list-head-next;free(temp);} else {struct Node *current list-head;while (current-next ! NULL current-next-data ! target) { // 查找要删除节点的前一个节点current current-next;}if (current-next ! NULL) { // 找到要删除的节点struct Node *temp current-next;current-next current-next-next;free(temp);}}
}实现查找操作
int search(struct LinkedList *list, int target) {struct Node *current list-head;while (current ! NULL) {if (current-data target) { // 找到匹配的节点return 1;}current current-next;}return 0; // 遍历完链表未找到匹配的节点
}实现遍历操作
void traverse(struct LinkedList *list) {struct Node *current list-head;while (current ! NULL) {printf(%d , current-data); // 访问节点的数据域current current-next;}
}这是一个简单的单链表实现示例。由于C语言需要手动管理内存因此在使用malloc函数分配内存时需要检查是否分配成功并在删除节点时需要使用free函数释放内存。您可以根据这个示例进行自定义扩展和适应具体需求。 双链表 双链表Doubly Linked List是一种常见的数据结构它与单链表相比在每个节点中都有两个指针分别指向前一个节点和后一个节点因此可以实现双向遍历。这使得在双链表中插入、删除节点等操作更加高效。
下面是一个更详细的双链表的 C 代码实现
#include stdio.h
#include stdlib.h// 双链表节点结构
typedef struct Node {int data;struct Node* prev;struct Node* next;
} Node;// 创建新节点
Node* createNode(int data) {Node* newNode (Node*)malloc(sizeof(Node));if (newNode NULL) {printf(内存分配失败\n);exit(1);}newNode-data data;newNode-prev NULL;newNode-next NULL;return newNode;
}// 在链表头部插入节点
void insertFront(Node** head, int data) {Node* newNode createNode(data);if (*head NULL) {*head newNode;} else {newNode-next *head;(*head)-prev newNode;*head newNode;}
}// 在链表末尾插入节点
void insertEnd(Node** head, int data) {Node* newNode createNode(data);if (*head NULL) {*head newNode;} else {Node* curr *head;while (curr-next ! NULL) {curr curr-next;}curr-next newNode;newNode-prev curr;}
}// 在指定位置插入节点
void insertAt(Node** head, int data, int position) {if (position 1) {printf(无效的位置\n);return;}if (position 1) {insertFront(head, data);return;}Node* newNode createNode(data);Node* curr *head;int count 1;while (count position - 1 curr ! NULL) {curr curr-next;count;}if (curr NULL) {printf(无效的位置\n);return;}newNode-next curr-next;newNode-prev curr;if (curr-next ! NULL) {curr-next-prev newNode;}curr-next newNode;
}// 删除链表头部节点
void deleteFront(Node** head) {if (*head NULL) {printf(链表为空\n);return;}Node* temp *head;*head (*head)-next;if (*head ! NULL) {(*head)-prev NULL;}free(temp);
}// 删除链表末尾节点
void deleteEnd(Node** head) {if (*head NULL) {printf(链表为空\n);return;}Node* curr *head;while (curr-next ! NULL) {curr curr-next;}if (curr-prev ! NULL) {curr-prev-next NULL;} else {*head NULL;}free(curr);
}// 删除指定位置节点
void deleteAt(Node** head, int position) {if (*head NULL || position 1) {printf(无效的位置\n);return;}if (position 1) {deleteFront(head);return;}Node* curr *head;int count 1;while (count position curr ! NULL) {curr curr-next;count;}if (curr NULL) {printf(无效的位置\n);return;}if (curr-prev ! NULL) {curr-prev-next curr-next;} else {*head curr-next;}if (curr-next ! NULL) {curr-next-prev curr-prev;}free(curr);
}// 打印链表
void printList(Node* head) {Node* curr head;while (curr ! NULL) {printf(%d , curr-data);curr curr-next;}printf(\n);
}int main() {Node* head NULL;// 插入节点insertFront(head, 1);insertEnd(head, 2);insertEnd(head, 3);insertAt(head, 4, 2);// 打印链表printf(双链表);printList(head);// 删除节点deleteFront(head);deleteEnd(head);deleteAt(head, 1);// 打印链表printf(删除节点后的双链表);printList(head);return 0;
}这段代码实现了双链表的创建节点、在链表头部、末尾和指定位置插入节点以及删除链表头部、末尾和指定位置节点并且可以打印链表。你可以根据自己的需求进行扩展和修改。
双链表的插入操作 双链表的插入操作有三种情况
在链表头部插入节点在链表末尾插入节点在指定位置插入节点
下面是这三种情况的详细说明和代码实现。
在链表头部插入节点
在链表头部插入节点只需要将新节点插入到原头节点前面并更新头节点的指针。
void insertFront(Node** head, int data) {Node* newNode createNode(data);if (*head NULL) {*head newNode;} else {newNode-next *head;(*head)-prev newNode;*head newNode;}
}在链表末尾插入节点
在链表末尾插入节点需要遍历整个链表找到最后一个节点并将新节点插入到最后一个节点后面。
void insertEnd(Node** head, int data) {Node* newNode createNode(data);if (*head NULL) {*head newNode;} else {Node* curr *head;while (curr-next ! NULL) {curr curr-next;}curr-next newNode;newNode-prev curr;}
}在指定位置插入节点
在指定位置插入节点需要遍历链表找到指定位置的节点并将新节点插入到该节点的前面并更新相邻节点的指针。
void insertAt(Node** head, int data, int position) {if (position 1) {printf(无效的位置\n);return;}if (position 1) {insertFront(head, data);return;}Node* newNode createNode(data);Node* curr *head;int count 1;while (count position - 1 curr ! NULL) {curr curr-next;count;}if (curr NULL) {printf(无效的位置\n);return;}newNode-next curr-next;newNode-prev curr;if (curr-next ! NULL) {curr-next-prev newNode;}curr-next newNode;
}注意如果指定位置为1则直接调用insertFront()函数插入节点。如果指定位置大于链表长度则插入失败输出错误信息。
上述代码中createNode()函数创建一个新节点Node** head表示指向头节点指针的指针因为在插入操作中需要修改头节点指针的值而头节点指针本身是一个指针变量所以需要使用指向指针的指针来实现修改。
双链表的删除操作 双链表的删除操作有三种情况
删除链表头部节点删除链表末尾节点删除指定位置节点
下面是这三种情况的详细说明和代码实现。
删除链表头部节点
删除链表头部节点只需要将头节点的下一个节点作为新的头节点并释放原头节点的内存。
void deleteFront(Node** head) {if (*head NULL) {printf(链表为空\n);return;}Node* temp *head;*head (*head)-next;if (*head ! NULL) {(*head)-prev NULL;}free(temp);
}删除链表末尾节点
删除链表末尾节点需要遍历整个链表找到最后一个节点并将倒数第二个节点的next指针置为NULL并释放最后一个节点的内存。
void deleteEnd(Node** head) {if (*head NULL) {printf(链表为空\n);return;}Node* curr *head;while (curr-next ! NULL) {curr curr-next;}if (curr-prev ! NULL) {curr-prev-next NULL;} else {*head NULL;}free(curr);
}删除指定位置节点
删除指定位置节点需要遍历链表找到指定位置的节点更新相邻节点的指针并释放目标节点的内存。
void deleteAt(Node** head, int position) {if (*head NULL || position 1) {printf(无效的位置\n);return;}if (position 1) {deleteFront(head);return;}Node* curr *head;int count 1;while (count position curr ! NULL) {curr curr-next;count;}if (curr NULL) {printf(无效的位置\n);return;}if (curr-prev ! NULL) {curr-prev-next curr-next;} else {*head curr-next;}if (curr-next ! NULL) {curr-next-prev curr-prev;}free(curr);
}注意如果指定位置为1则直接调用deleteFront()函数删除头部节点。如果指定位置大于链表长度则删除失败输出错误信息。
上述代码中Node** head表示指向头节点指针的指针因为在删除操作中需要修改头节点指针的值而头节点指针本身是一个指针变量所以需要使用指向指针的指针来实现修改。
循环链表 循环链表是一种特殊的链表它与普通链表的区别在于最后一个节点的next指针不是指向NULL而是指向第一个节点从而形成一个环形结构。
循环链表有两种基本类型单向循环链表和双向循环链表。单向循环链表中每个节点只有一个指针域即指向下一个节点的指针而双向循环链表中每个节点有两个指针域即分别指向前一个节点和后一个节点的指针。
下面是一个单向循环链表的定义
typedef struct Node {int data;struct Node* next;
} Node;typedef struct CircularLinkedList {Node* head;
} CircularLinkedList;在单向循环链表中头节点的next指针指向第一个节点而最后一个节点的next指针则指向头节点。
循环链表的插入和删除操作与普通链表类似唯一的区别是在插入和删除末尾节点时需要特殊处理因为末尾节点的next指针指向头节点而非NULL。
下面是一个简单的单向循环链表的插入和删除操作的示例代码
// 创建新节点
Node* createNode(int data) {Node* newNode (Node*)malloc(sizeof(Node));newNode-data data;newNode-next NULL;return newNode;
}// 在链表末尾插入节点
void insertEnd(CircularLinkedList* list, int data) {Node* newNode createNode(data);if (list-head NULL) {list-head newNode;newNode-next list-head;} else {Node* curr list-head;while (curr-next ! list-head) {curr curr-next;}curr-next newNode;newNode-next list-head;}
}// 删除指定位置的节点
void deleteAt(CircularLinkedList* list, int position) {if (list-head NULL) {printf(链表为空\n);return;}Node* curr list-head;Node* prev NULL;int count 1;while (count position curr-next ! list-head) {prev curr;curr curr-next;count;}if (count position) {printf(无效的位置\n);return;}if (prev NULL) {Node* tail list-head;while (tail-next ! list-head) {tail tail-next;}list-head curr-next;tail-next list-head;} else {prev-next curr-next;}free(curr);
}注意上述代码中在删除末尾节点时需要特判。如果目标节点是头节点则需要更新头节点指针的值并将最后一个节点的next指针指向新的头节点。如果目标节点不是头节点则直接更新相邻节点的指针即可。
循环链表的遍历和其他操作与普通链表类似只需要判断是否回到了头节点即可。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/932139.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!