void clearList(Plinklist list){
while(list->next != NULL){
deleteHead(list);
printf("表已被清空!\n");
分三个文件进行,①接口文件blinklist.h、②blinklist.c、③blinklist_main.c
①blinklist.h
#ifndef _BLINKLIST_H_
#define _BLINKLIST_H_
#include <stdio.h>
#include <stdlib.h>
typedef int typData;
typedef struct Node {
typData data;
int tail;
struct Node *prev;
struct Node *next;
} Linklist, *Plinklist;
Plinklist createLinkedList(Plinklist *list);
int isEmpty(Plinklist list);
void insertAtHead(Plinklist list, typData value);
void insertAtTail(Plinklist list, typData value);
void insertAtPosition(Plinklist list, int position, typData value);
void deleteHead(Plinklist list);
void deleteTail(Plinklist list);
void deleteAtPosition(Plinklist list, int position);
int findPositionByValue(Plinklist list, typData value);
int findValueByPosition(Plinklist list, int position);
void modifyByPosition(Plinklist list, int position, typData value);
void modifyValue(Plinklist list, typData oidValue, typData newValue);
int getLength(Plinklist list);
void prev_traverse(Plinklist list);
void next_traverse(Plinklist list);
void clearList(Plinklist list);
#endif
②blinklist.c
#include "blinklist.h"
// 链表节点结构体
typedef struct Node {
typData data;// 节点数据
int tail;//记录节点数
struct Node *prev;//指向上一个节点的指针
struct Node *next;//指向下一个节点的指针
} Linklist, *Plinklist;
Plinklist createLinkedList(Plinklist *list){
(*list) = (Plinklist)malloc(sizeof(Linklist));
if(list == NULL){
perror("createLinkedList list malloc");
(*list)->tail = 0;
(*list)->prev = NULL;
(*list)->next = NULL;
return *list;
int isEmpty(Plinklist list){
if(list == NULL || list->tail == 0){
return 1;
}else{
return 0;
void insertAtHead(Plinklist list, typData value){
if(list == NULL){
puts("insert head arg err");
return ;
Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
if(newNode == NULL){
perror("insert head newNode malloc");
return ;
newNode->data = value;
newNode->prev = list;
newNode->next = list->next;
if(list->next != NULL){
list->next->prev = newNode;更新头节点的前驱节点为新节点
list->next = newNode;
list->tail++;
void insertAtTail(Plinklist list, typData value){
if(list == NULL){
puts("insert tail arg err");
return ;
Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
if(newNode == NULL){
perror("insert tail newNode malloc");
return ;
newNode->data = value;
newNode->next = NULL;
Plinklist current_tail = list;
while(current_tail->next != NULL){
current_tail = current_tail->next;
newNode->prev = current_tail;
current_tail->next = newNode;
list->tail++;
void insertAtPosition(Plinklist list, int position, typData value){
if(list ==NULL){
puts("insert position arg err");
return ;
if(position < 0 || position > (list->tail)){
puts("无效位置!");
return ;
Plinklist newNode = (Plinklist)malloc(sizeof(Linklist));
newNode->data = value;
Plinklist current = list;
int count = 0;
while(current != NULL && count < position){
current = current->next;
count++;
newNode->next = current->next;
newNode->prev = current;
if (current->next !=
NULL) {
current->next->prev = newNode;
current->next = newNode;
list->tail++;
void deleteHead(Plinklist list){
if(list ==NULL){
puts("dalete head arg err");
return ;
if(isEmpty(list)){
puts("表是空的!");
return;
Plinklist deleteHead = list->next;
list->next = deleteHead->next;
if (deleteHead->next != NULL) {
deleteHead->next->prev = list;
free(deleteHead);
list->tail--;
void deleteTail(Plinklist list){
if(list ==NULL){
puts("dalete tail arg err");
return ;
if(isEmpty(list)){
puts("表是空的!");
return;
Plinklist current = list;
while(current->next != NULL && current->next->next != NULL){
current = current->next;
Plinklist deleteTail = current->next;
current->next = NULL;
if (deleteTail != NULL) {
free(deleteTail);
list->tail--;
void deleteAtPosition(Plinklist list, int position){
if (isEmpty(list)) {
printf("链表为空,删不了,根本删不了\n");
return;
Plinklist current = list;
int count = 0;
while (current->next != NULL && count < position) {
current = current->next;
count++;
if (current->next == NULL) {
printf("无效的删除位置\n");
return;
Plinklist deletePosition = current->next;
current->next = deletePosition->next;
if (deletePosition->next != NULL) {
deletePosition->next->prev = current;
free(deletePosition);
list->tail--;
if (isEmpty(list)) {
printf("链表为空,删不了了,根本删不了了\n");
return;
int findPositionByValue(Plinklist list, typData value){
if(list ==NULL){
puts("findValue Position arg err");
return -1;
if(isEmpty(list)){
puts("表是空的!");
return -1;
Plinklist current = list->next;
int position = 0;
while (current != NULL) {
if (current->data == value) {
return position;
current = current->next;
position++;
printf("没有该值!");
return -1;
int findValueByPosition(Plinklist list, int position){
if(list ==NULL){
puts("findPosition Value arg err");
return -1;
if(isEmpty(list)){
puts("表是空的!");
return -1;
Plinklist current = list->next;
int count = 0;
while (current != NULL && count < position) {
current = current->next;
count++;
if (current == NULL) {
printf("无效的下标\n");
return -1;
return current->data;
void modifyByPosition(Plinklist list, int
position, typData value){
if(list ==NULL){
puts("modifyPosition Value arg err");
return ;
if(isEmpty(list)){
puts("表是空的!");
return ;
if (isEmpty(list)) {
printf("链表为空,无法修改元素\n");
return;
Plinklist current = list->next;
int count = 0;
while (current != NULL && count < position) {
current = current->next;
count++;
if (current == NULL) {
printf("无效的下标\n");
return;
current->data = value;
void modifyValue(Plinklist list, typData oldValue, typData newValue){
if(list ==NULL){
puts("modifyValue Value arg err");
return ;
if (isEmpty(list)) {
printf("链表为空,无法修改节点值\n");
return;
Plinklist current = list->next;
while (current != NULL) {
if (current->data == oldValue) {
current->data = newValue;
return;
current = current->next;
printf("未找到目标值\n");
int getLength(Plinklist list){
if(isEmpty(list)){
return -1;
return list->tail;
void prev_traverse(Plinklist list){
if(list == NULL){
puts("prev_traverse arg err");
return ;
if(isEmpty(list)){
return ;
Plinklist current_tail = list;
while(current_tail->next != NULL){
current_tail = current_tail->next;
Plinklist current = current_tail;
while(current != list){
printf("%d ",current->data);
current = current->prev;
printf("\n");
void next_traverse(Plinklist list){
if(list == NULL){
puts("next_traverse arg err");
return ;
if(isEmpty(list)){
return ;
Plinklist current = list->next;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
printf("\n");
void clearList(Plinklist list){
while(list->next != NULL){
deleteHead(list);
printf("表已被清空!\n");
③blinklist_main.c
#include "blinklist.h"
#include "blinklist.c"
int main() {
Plinklist list;
createLinkedList(&list);
int choice, value, position, oldValue, newValue;
while (1) {
printf("\n*****************************链表操作菜单*****************************\n");
printf("1. 在头部插入元素 2. 在尾部插入元素 3. 在任意位置插入元素\n");
printf("4. 删除头节点 5. 删除尾节点 6. 删除任意位置的节点\n");
printf("7. 按值查找元素的位置 8. 按位置查找元素的值 9. 修改指定位置的节点值\n");
printf("10. 修改指定值的节点值 11. 获取链表长度 12. 遍历链表\n");
printf("13. 清空链表 14. 退出程序\n");
printf("*********************************************************************\n");
printf("请输入操作编号:");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("请输入要插入的元素值:");
scanf("%d", &value);
insertAtHead(list, value);
printf("向后遍历:");
prev_traverse
(list);
printf("向前遍历:");
next_traverse(list);
break;
case 2:
printf("请输入要插入的元素值:");
scanf("%d", &value);
insertAtTail(list, value);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 3:
printf("请输入要插入的位置:");
scanf("%d", &position);
printf("请输入要插入的元素值:");
scanf("%d", &value);
insertAtPosition(list, position, value);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 4:
deleteHead(list);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 5:
deleteTail(list);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 6:
printf("请输入要删除的位置:");
scanf("%d", &position);
deleteAtPosition(list, position);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 7:
printf("请输入要查找的元素值:");
scanf("%d", &value);
position = findPositionByValue(list, value);
if (position != -1) {
printf("元素值 %d 的位置是:%d\n", value, position);
break;
case 8:
printf("请输入要查找的位置:");
scanf("%d", &position);
value = findValueByPosition(list, position);
if (value != -1) {
printf("位置 %d 上的元素值是:%d\n", position, value);
break;
case 9:
printf("请输入要修改的位置:");
scanf("%d", &position);
printf("请输入修改后的元素值:");
scanf("%d", &value);
modifyByPosition(list, position, value);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 10:
printf("请输入要修改的元素值:");
scanf("%d", &oldValue);
printf("请输入修改后的元素值:");
scanf("%d", &newValue);
modifyValue(list, oldValue, newValue);
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 11:
printf("链表的长度是:%d\n", getLength(list));
break;
case 12:
printf("向后遍历:");
prev_traverse(list);
printf("向前遍历:");
next_traverse(list);
break;
case 13:
clearList(list);
break;
case 14:
printf("已退出!!\n");
exit(0);
default:
printf("无效的操作编号!\n");
break;
return 0;
我们将解释双向不循环链表的概念,并说明每个节点的结构。每个节点包含一个数据元素,一个指向前一个节点的指针(prev),以及一个指向下一个节点的指针(next)。四、数据结构——单向链表的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表
这里的顺序比较容易记住,就是自己写代码的时候可能会比较迷糊,我是这样记得,箭头从起点到终点的方向为等式的左边,箭头的终点为等式的右边,拿①举例子,箭头的方向为node->prev,箭头的终点为head,所以第一步为node->prev = head。
Node * node = new Node;
文章目录1.头插法2.尾插法3.删除元素4.打印元素总结
链表是一种常见的基础数据结构,结构体指针,下面用c语言实现单链表插入,删除,打印等基本操作
1.头插法
头插法:从一个空表开始,重复读入数据,生成新节点,将读入的数据域存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点之后,直至读入结束为止
头插法图解
头插法代码
//插入元素(头插法)
int insertheadList...
单链表的一个优点是结构简单,但是它也有一个缺点,即在单链表中只能通过一个结点的引用访问其后续结点,而无法直接访问其前驱结点,
要在单链表中找到某个结点的前驱结点,必须从链表的首结点出发依次向后寻找,但是需要Ο(n)时间。
为此我们可以扩展单链表的结点结构,使得通过一个结点的引用,不但能够访问其后续结点,也可以方便的访问其前驱结点。
扩展单链表结点结构的方法是,在单链表结点结构中新增加一...
双向链表的操作问题
Description
建立一个长度为n的带头结点的双向链表,使得该链表中的数据元素递增有序排列。(必须使用双向链表完成,数据类型为整型。)
Input
第一行:双向表的长度;
第二行:链表中的数据元素。
Output
输出双向链表中的数据元素的值。 Sample Input
2 4 6 3 5 8 10 21 12 9Sample
上午写了下单向循环链表的程序,今天下午我把双向链表的程序写完了。其实双向链表和单向链表也是有很多相似的地方的,听名字可以猜到,每个节点都包含两个指针,一个指针指向上一个节点,一个指针指向下一个节点。这里有两个特殊的地方,第一就是头节点的一个指针指向NULL空指针(没有前驱节点),第二就是尾节点的一个指针指向NULL指针(没有后继节点)。
我们可以看下双向链表的示意图(自己画的比较难看):
头插法和尾插法是在链表数据结构中常见的两种插入元素的方法。
头插法的核心思想是将新节点插入到链表的头部。在带头结点方式实现头插法时,首先创建一个新节点,并将新节点的next指针指向当前链表的头节点,再将头节点指向新节点。而在不带头结点方式实现头插法时,直接将新节点的next指针指向当前链表的头节点,再将头节点指向新节点。
尾插法的核心思想是将新节点插入到链表的尾部。在带头结点方式实现尾插法时,首先创建一个新节点,并将新节点的next指针置为NULL,然后找到链表的尾节点,将尾节点的next指针指向新节点。而在不带头结点方式实现尾插法时,先判断链表是否为空,若为空则将新节点作为链表的头节点,否则找到链表的尾节点,将尾节点的next指针指向新节点。
关于代码实现,可以利用结构体和指针来定义链表节点的数据结构,如引用所示。然后根据需要选择头插法或尾插法,使用相关的代码段来实现插入操作,如引用所示。具体的插入过程中,可以根据具体需求在新节点中设置相关的数据信息。最后,通过运行程序可以得到链表插入操作的结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
#### 引用[.reference_title]
- *1* *3* [【数据结构】:单链表之头插法和尾插法(动图+图解)](https://blog.csdn.net/weixin_46629453/article/details/125643226)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"]
- *2* [链表的三种插入方法(头插法,尾插法,任意位置插入)](https://blog.csdn.net/weixin_63032791/article/details/122089859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"]
[ .reference_list ]