388 lines
10 KiB
C
388 lines
10 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
// 定义双向链表节点结构体
|
|
struct Node
|
|
{
|
|
int data;
|
|
struct Node *prev;
|
|
struct Node *next;
|
|
};
|
|
|
|
// 定义双向链表结构体
|
|
struct DoubleList
|
|
{
|
|
struct Node *head;
|
|
struct Node *tail;
|
|
};
|
|
|
|
// 初始化双向链表
|
|
void initDoubleList(struct DoubleList *list)
|
|
{
|
|
list->head = NULL;
|
|
list->tail = NULL;
|
|
}
|
|
|
|
// 获取双向链表长度
|
|
int getListLength(struct DoubleList *list)
|
|
{
|
|
int length = 0;
|
|
struct Node *current = list->head;
|
|
while (current != NULL)
|
|
{
|
|
length++;
|
|
current = current->next;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
// 向双向链表头部添加节点
|
|
void addNodeToHead(struct DoubleList *list, int data)
|
|
{
|
|
// 分配新节点内存
|
|
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
|
|
newNode->data = data;
|
|
newNode->prev = NULL;
|
|
newNode->next = list->head;
|
|
|
|
// 如果链表为空,则新节点同时是头节点和尾节点
|
|
if (list->head == NULL)
|
|
{
|
|
list->tail = newNode;
|
|
}
|
|
else
|
|
{
|
|
list->head->prev = newNode;
|
|
}
|
|
|
|
// 更新头节点为新节点
|
|
list->head = newNode;
|
|
}
|
|
|
|
// 向双向链表尾部添加节点
|
|
void addNodeToTail(struct DoubleList *list, int data)
|
|
{
|
|
// 分配新节点内存
|
|
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
|
|
newNode->data = data;
|
|
newNode->prev = list->tail;
|
|
newNode->next = NULL;
|
|
|
|
// 如果链表为空,则新节点同时是头节点和尾节点
|
|
if (list->tail == NULL)
|
|
{
|
|
list->head = newNode;
|
|
}
|
|
else
|
|
{
|
|
list->tail->next = newNode;
|
|
}
|
|
|
|
// 更新尾节点为新节点
|
|
list->tail = newNode;
|
|
}
|
|
|
|
// 在指定位置插入节点
|
|
void insertNode(struct DoubleList *list, int data, int position)
|
|
{
|
|
// 分配新节点内存
|
|
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
|
|
newNode->data = data;
|
|
|
|
// 如果插入位置为0,则在头部插入
|
|
if (position == 0)
|
|
{
|
|
addNodeToHead(list, data);
|
|
}
|
|
// 如果插入位置大于等于链表长度,则在尾部插入
|
|
else if (position >= getListLength(list))
|
|
{
|
|
addNodeToTail(list, data);
|
|
}
|
|
|
|
// 否则,在指定位置插入
|
|
else
|
|
{
|
|
// 首先遍历到指定位置
|
|
struct Node *current = list->head;
|
|
for (int i = 0; i < position; i++)
|
|
{
|
|
current = current->next;
|
|
}
|
|
|
|
// 然后插入到指定位置
|
|
newNode->prev = current->prev;
|
|
newNode->next = current;
|
|
|
|
// 更新当前节点的前一个节点的next指针
|
|
current->prev->next = newNode;
|
|
|
|
// 更新当前节点的前指针为新节点
|
|
current->prev = newNode;
|
|
}
|
|
}
|
|
|
|
// 删除指定位置的节点
|
|
int delectNode(struct DoubleList *list, int position)
|
|
{
|
|
// 如果删除位置为0,则删除头节点
|
|
if (position == 0)
|
|
{
|
|
// 如果链表只有一个节点,则删除后链表为空
|
|
if (list->head == list->tail)
|
|
{
|
|
free(list->head);
|
|
list->head = NULL;
|
|
list->tail = NULL;
|
|
}
|
|
else
|
|
{
|
|
// 更新头节点为下一个节点
|
|
list->head = list->head->next;
|
|
// 释放旧头节点内存,更新新头节点的prev指针为NULL
|
|
free(list->head->prev);
|
|
list->head->prev = NULL;
|
|
}
|
|
return 1;
|
|
}
|
|
// 如果删除位置大于等于链表长度,则删除尾节点
|
|
else if (position >= getListLength(list))
|
|
{
|
|
// 更新尾节点为前一个节点
|
|
list->tail = list->tail->prev;
|
|
// 释放旧尾节点内存,更新新尾节点的next指针为NULL
|
|
free(list->tail->next);
|
|
list->tail->next = NULL;
|
|
return 1;
|
|
}
|
|
// 如果删除位置在中间,则删除指定位置节点
|
|
else
|
|
{
|
|
// 首先遍历到指定位置
|
|
struct Node *current = list->head;
|
|
for (int i = 0; i < position; i++)
|
|
{
|
|
current = current->next;
|
|
}
|
|
// 更新前一个节点的next指针为后一个节点
|
|
current->prev->next = current->next;
|
|
|
|
// 更新后一个节点的prev指针为前一个节点,更新当前节点的next指针为NULL
|
|
current->next->prev = current->prev;
|
|
|
|
free(current);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// 修改指定位置节点的数据
|
|
int modifyNode(struct DoubleList *list, int data, int position)
|
|
{
|
|
// 首先遍历到指定位置
|
|
struct Node *current = list->head;
|
|
for (int i = 0; i < position; i++)
|
|
{
|
|
current = current->next;
|
|
}
|
|
// 修改节点数据
|
|
current->data = data;
|
|
return 1;
|
|
}
|
|
|
|
// 查找指定数据的节点位置
|
|
int findNodePosition(struct DoubleList *list, int data)
|
|
{
|
|
// 从头节点开始遍历
|
|
struct Node *current = list->head;
|
|
int position = 0;
|
|
while (current != NULL)
|
|
{
|
|
// 如果找到匹配数据,则返回当前位置
|
|
if (current->data == data)
|
|
{
|
|
return position;
|
|
}
|
|
// 否则,继续遍历下一个节点
|
|
current = current->next;
|
|
position++;
|
|
}
|
|
// 如果遍历完链表仍未找到匹配数据,则返回-1
|
|
return -1;
|
|
}
|
|
|
|
// 查找指定位置的节点数据
|
|
int findNodeData(struct DoubleList *list, int position)
|
|
{
|
|
// 首先遍历到指定位置
|
|
struct Node *current = list->head;
|
|
for (int i = 0; i < position; i++)
|
|
{
|
|
current = current->next;
|
|
}
|
|
// 返回当前节点数据
|
|
return current->data;
|
|
}
|
|
|
|
// 打印链表所有节点数据
|
|
void printList(struct DoubleList *list)
|
|
{
|
|
// 从头节点开始遍历
|
|
struct Node *current = list->head;
|
|
while (current != NULL)
|
|
{
|
|
// 打印当前节点数据
|
|
printf("%d ", current->data);
|
|
// 继续遍历下一个节点
|
|
current = current->next;
|
|
}
|
|
// 打印换行符
|
|
printf("\n");
|
|
}
|
|
|
|
int main()
|
|
{
|
|
// 设置控制台编码为UTF-8,防止中文乱码
|
|
#ifdef _WIN32
|
|
system("chcp 65001 > nul"); // 设置控制台编码为UTF-8
|
|
SetConsoleOutputCP(65001); // 设置控制台输出编码
|
|
SetConsoleCP(65001); // 设置控制台输入编码
|
|
#endif
|
|
|
|
// 初始化双端链表
|
|
struct DoubleList list;
|
|
initDoubleList(&list);
|
|
|
|
// 输入节点数据
|
|
printf("请输入初始节点数据的数量(默认在链表尾端插入):");
|
|
int count;
|
|
scanf("%d", &count);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
printf("请输入第 %d 个节点数据:", i + 1);
|
|
int data;
|
|
scanf("%d", &data);
|
|
addNodeToTail(&list, data);
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
// 打印菜单
|
|
printf("1. 插入节点\n");
|
|
printf("2. 删除节点\n");
|
|
printf("3. 修改节点\n");
|
|
printf("4. 查找节点\n");
|
|
printf("5. 打印链表\n");
|
|
printf("0. 退出程序\n");
|
|
printf("请输入操作选择:");
|
|
int choice;
|
|
scanf("%d", &choice);
|
|
|
|
// 根据选择执行相应操作
|
|
switch (choice)
|
|
{
|
|
case 1:
|
|
printf("1. 在链表头插入节点\n");
|
|
printf("2. 在链表尾插入节点\n");
|
|
printf("3. 在指定位置插入节点\n");
|
|
printf("请输入插入方式选择:");
|
|
int addchoice;
|
|
scanf("%d", &addchoice);
|
|
|
|
printf("请输入要插入的数据:");
|
|
int insertData;
|
|
scanf("%d", &insertData);
|
|
switch (addchoice)
|
|
{
|
|
case 1:
|
|
addNodeToHead(&list, insertData);
|
|
break;
|
|
case 2:
|
|
addNodeToTail(&list, insertData);
|
|
break;
|
|
case 3:
|
|
printf("请输入要插入的位置:");
|
|
int insertPosition;
|
|
scanf("%d", &insertPosition);
|
|
insertNode(&list, insertData, insertPosition);
|
|
break;
|
|
default:
|
|
printf("无效选择,请重新输入\n");
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
printf("请输入要删除的位置:");
|
|
int deletePosition;
|
|
scanf("%d", &deletePosition);
|
|
delectNode(&list, deletePosition);
|
|
break;
|
|
case 3:
|
|
printf("请输入要修改的数据:");
|
|
int modifyData;
|
|
scanf("%d", &modifyData);
|
|
printf("请输入要修改的位置:");
|
|
int modifyPosition;
|
|
scanf("%d", &modifyPosition);
|
|
modifyNode(&list, modifyData, modifyPosition);
|
|
break;
|
|
case 4:
|
|
printf("1. 查找指定数据的节点位置\n");
|
|
printf("2. 查找指定位置的节点数据\n");
|
|
printf("请输入查找方式选择:");
|
|
int findchoice;
|
|
scanf("%d", &findchoice);
|
|
switch (findchoice)
|
|
{
|
|
case 1:
|
|
printf("请输入要查找的数据:");
|
|
int findData;
|
|
scanf("%d", &findData);
|
|
int position = findNodePosition(&list, findData);
|
|
if (position != -1)
|
|
{
|
|
printf("数据 %d 位于链表第 %d 个节点\n", findData, position);
|
|
}
|
|
else
|
|
{
|
|
printf("链表中不存在数据 %d\n", findData);
|
|
}
|
|
break;
|
|
case 2:
|
|
printf("请输入要查找的位置:");
|
|
int findPosition;
|
|
scanf("%d", &findPosition);
|
|
int data = findNodeData(&list, findPosition);
|
|
if (data != -1)
|
|
{
|
|
printf("链表第 %d 个节点的数据为 %d\n", findPosition, data);
|
|
}
|
|
else
|
|
{
|
|
printf("链表中不存在第 %d 个节点\n", findPosition);
|
|
}
|
|
break;
|
|
default:
|
|
printf("无效选择,请重新输入\n");
|
|
break;
|
|
}
|
|
break;
|
|
case 5:
|
|
printList(&list);
|
|
break;
|
|
case 0:
|
|
printf("程序退出\n");
|
|
return 0;
|
|
default:
|
|
printf("无效选择,请重新输入\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
} |