总结与反思:
1,优点:与单链表相比双链表提供了反向遍历的能力,每个节点都环环相扣
2,缺点:比起单链表要操作更多,得把*previous指向前一节点,所以结构体也多了一个指向前一节点的指针,更占空间
3,我的建议是单链表就够用了
学习目标:
学会双向链表. 主要是为了练习链表的变种, 寻找更多设计的感觉. 这样在面对实际问题的时候, 就具有一定的建模能力.
学习指导:帆神的代码
学习任务:
3. 代码说明
- 实现了打印、插入、定位、删除.
- 每个相关指针都要改, 必须画个图来辅助写程序.
- 尾结点删除时需要注意. 需要进行边界测试.
学习时间:
2022.5.3
1抄写代码
1.1双链表结构体
/**
* 双链表结构体,存储字符串数据
*/
typedef struct DoubleLinkeNdode {
char data;
struct DoubleLinkeNdode *previous;
struct DoubleLinkeNdode *next;
} DLNode, *DLNodePtr;
1.2初始化链表
/**
* @brief 初始化链表,创建一个头节点
*
* @return 返回头节点
*/
DLNodePtr initLinkList() {
//申请空间
DLNodePtr tempHeader = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
//初始化
tempHeader->data = '\0';
tempHeader->previous = NULL;
tempHeader->next = NULL;
return tempHeader;
}
1.3打印链表
/**
* @brief 打印链表
*
* @param paraHeader 传入头节点
*/
void printList(DLNodePtr paraHeader) {
DLNodePtr p = paraHeader->next;
//节点不为空,则打印数据
while (p != NULL) {
printf("%c", p->data);
p = p->next;
}
printf("\n");
}
1.4插入节点
/**
* @brief 插入一个节点操作
*
* @param paraChar
* @param paraHeader
* @param paraPosition
*/
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition) {
//创建三个结构体变量:p查找查找插入链表位置,q申请新空间,r插入节点的后一节点,辅助插入
DLNodePtr p, q, r;
//1查找插入链表位置
p = paraHeader;
for (int i = 0; i < paraPosition; i++) {
p = p->next;
if (p == NULL) {
printf("位置%d已经超出链表范围\n", paraPosition);
return;
}
}
//2申请空间
q = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
//赋值
q->data = paraChar;
//3把新节点插入双链表
r = p->next;
q->next = p->next;
q->previous = p;
p->next = q;
//如果不是尾节点,才需要把插入节点的后一节点指向插入节点(非常巧妙)
if (r != NULL) {
r->previous = q;
}
printf("插入元素%c成功!\n", paraChar);
}
1.5删除节点
/**
* @brief 删除一个节点操作
*
* @param paraChar
* @param paraHeader
*/
void deleteElement(DLNodePtr paraHeader, char paraChar) {
//创建三个结构体变量:p为查找传入数据的前节点
DLNodePtr p, q, r;
//1查找传入数据的前节点
p = paraHeader;
while ((p->next != NULL) && (p->next->data != paraChar)) {
p = p->next;
}
//2找不到数据,提示并结束
if (p->next == NULL) {
printf("节点%c不存在\n", paraChar);
return;
}
//3找到数据,删除并提示
q = p->next;
r = q->next;
p->next = r;
if (r != NULL) {
r->previous = p;
}
printf("你已经删除了节点%c", q->data);
free(q);
}
2.定位节点
/**
* @brief 定位节点
*
* @param paraChar
* @param paraHeader
*
* @return
*/
int locateElement(DLNodePtr paraHeader, char paraChar) {
DLNodePtr p = paraHeader;
for (int i = 0; p != NULL; i++) {
if (p->data == paraChar) return i;
p = p->next;
}
return -1;
}
3.单元测试
3.1增删
/**
* 单元测试
*/
void insertDeleteTest() {
printf("----insertDeleteTest开始测试-----\n");
DLNodePtr tempList = initLinkList();
printList(tempList);
insertElement(tempList, 'H', 0);
insertElement(tempList, 'e', 1);
insertElement(tempList, 'l', 2);
insertElement(tempList, 'l', 3);
insertElement(tempList, 'o', 4);
insertElement(tempList, '!', 5);
printList(tempList);
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
insertElement(tempList, 'o', 1);
printList(tempList);
printf("--------------**********-------------\n\n");
}
3.2定位
/**
* 单元测试2
*/
void insertLocateTest() {
printf("----insertLocateTest开始测试-----\n");
int location, data;
DLNodePtr tempList = initLinkList();
printList(tempList);
insertElement(tempList, 'H', 0);
insertElement(tempList, 'e', 1);
insertElement(tempList, 'l', 2);
insertElement(tempList, 'l', 3);
insertElement(tempList, 'o', 4);
insertElement(tempList, '!', 5);
printList(tempList);
data = 'e';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
data = 'a';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
data = 'o';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
printList(tempList);
insertElement(tempList, 'o', 1);
printList(tempList);
printf("--------------**********-------------\n\n");
}
3.3地址分配
/**
* 地址分配测试
*/
void basicAddressTest() {
printf("------basicAddressTest开始测试-------\n");
DLNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode1.next = NULL;
tempNode2.data = 6;
tempNode2.next = NULL;
printf("第一个节点,data,next: %d, %d, %d\r\n",
&tempNode1, &tempNode1.data, &tempNode1.next);
printf("第二个节点,data,next: %d, %d, %d\r\n",
&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
printf("--------------**********-------------\n\n");
}
3.4运行结果
----insertDeleteTest开始测试-----
插入元素H成功!
插入元素e成功!
插入元素l成功!
插入元素l成功!
插入元素o成功!
插入元素!成功!
Hello!
你已经删除了节点e节点a不存在
你已经删除了节点oHll!
插入元素o成功!
Holl!
--------------**********-------------
----insertLocateTest开始测试-----
插入元素H成功!
插入元素e成功!
插入元素l成功!
插入元素l成功!
插入元素o成功!
插入元素!成功!
Hello!
元素e的位置是2
找不到元素a!!!
元素o的位置是5
Hello!
插入元素o成功!
Hoello!
--------------**********-------------
------basicAddressTest开始测试-------
第一个节点,data,next: -834668016, -834668016, -834668000
第二个节点,data,next: -834668048, -834668048, -834668032
--------------**********-------------
--------------------------------
Process exited after 0.06356 seconds with return value 0
Press ANY key to continue...
4全部代码
#include <stdio.h>
#include <malloc.h>
/**
* 双链表结构体,存储字符串数据
*/
typedef struct DoubleLinkeNdode {
char data;
struct DoubleLinkeNdode *previous;
struct DoubleLinkeNdode *next;
} DLNode, *DLNodePtr;
/**
* @brief 初始化链表,创建一个头节点
*
* @return 返回头节点
*/
DLNodePtr initLinkList() {
//申请空间
DLNodePtr tempHeader = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
//初始化
tempHeader->data = '\0';
tempHeader->previous = NULL;
tempHeader->next = NULL;
return tempHeader;
}
/**
* @brief 打印链表
*
* @param paraHeader 传入头节点
*/
void printList(DLNodePtr paraHeader) {
DLNodePtr p = paraHeader->next;
//节点不为空,则打印数据
while (p != NULL) {
printf("%c", p->data);
p = p->next;
}
printf("\n");
}
/**
* @brief 插入一个节点操作
*
* @param paraChar
* @param paraHeader
* @param paraPosition
*/
void insertElement(DLNodePtr paraHeader, char paraChar, int paraPosition) {
//创建三个结构体变量:p查找查找插入链表位置,q申请新空间,r插入节点的后一节点,辅助插入
DLNodePtr p, q, r;
//1查找插入链表位置
p = paraHeader;
for (int i = 0; i < paraPosition; i++) {
p = p->next;
if (p == NULL) {
printf("位置%d已经超出链表范围\n", paraPosition);
return;
}
}
//2申请空间
q = (DLNodePtr)malloc(sizeof(struct DoubleLinkeNdode) * 1);
//赋值
q->data = paraChar;
//3把新节点插入双链表
r = p->next;
q->next = p->next;
q->previous = p;
p->next = q;
//如果不是尾节点,才需要把插入节点的后一节点指向插入节点(非常巧妙)
if (r != NULL) {
r->previous = q;
}
printf("插入元素%c成功!\n", paraChar);
}
/**
* @brief 删除一个节点操作
*
* @param paraChar
* @param paraHeader
*/
void deleteElement(DLNodePtr paraHeader, char paraChar) {
//创建三个结构体变量:p为查找传入数据的前节点
DLNodePtr p, q, r;
//1查找传入数据的前节点
p = paraHeader;
while ((p->next != NULL) && (p->next->data != paraChar)) {
p = p->next;
}
//2找不到数据,提示并结束
if (p->next == NULL) {
printf("节点%c不存在\n", paraChar);
return;
}
//3找到数据,删除并提示
q = p->next;
r = q->next;
p->next = r;
if (r != NULL) {
r->previous = p;
}
printf("你已经删除了节点%c", q->data);
free(q);
}
/**
* @brief 定位节点
*
* @param paraChar
* @param paraHeader
*
* @return
*/
int locateElement(DLNodePtr paraHeader, char paraChar) {
DLNodePtr p = paraHeader;
for (int i = 0; p != NULL; i++) {
if (p->data == paraChar) return i;
p = p->next;
}
return -1;
}
/**
* 单元测试
*/
void insertDeleteTest() {
printf("----insertDeleteTest开始测试-----\n");
DLNodePtr tempList = initLinkList();
printList(tempList);
insertElement(tempList, 'H', 0);
insertElement(tempList, 'e', 1);
insertElement(tempList, 'l', 2);
insertElement(tempList, 'l', 3);
insertElement(tempList, 'o', 4);
insertElement(tempList, '!', 5);
printList(tempList);
deleteElement(tempList, 'e');
deleteElement(tempList, 'a');
deleteElement(tempList, 'o');
printList(tempList);
insertElement(tempList, 'o', 1);
printList(tempList);
printf("--------------**********-------------\n\n");
}
/**
* 单元测试2
*/
void insertLocateTest() {
printf("----insertLocateTest开始测试-----\n");
int location, data;
DLNodePtr tempList = initLinkList();
printList(tempList);
insertElement(tempList, 'H', 0);
insertElement(tempList, 'e', 1);
insertElement(tempList, 'l', 2);
insertElement(tempList, 'l', 3);
insertElement(tempList, 'o', 4);
insertElement(tempList, '!', 5);
printList(tempList);
data = 'e';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
data = 'a';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
data = 'o';
location = locateElement(tempList, data);
if (location == -1) {
printf("找不到元素%c!!!\n", data);
} else {
printf("元素%c的位置是%d\n", data, location);
}
printList(tempList);
insertElement(tempList, 'o', 1);
printList(tempList);
printf("--------------**********-------------\n\n");
}
/**
* 地址分配测试
*/
void basicAddressTest() {
printf("------basicAddressTest开始测试-------\n");
DLNode tempNode1, tempNode2;
tempNode1.data = 4;
tempNode1.next = NULL;
tempNode2.data = 6;
tempNode2.next = NULL;
printf("第一个节点,data,next: %d, %d, %d\r\n",
&tempNode1, &tempNode1.data, &tempNode1.next);
printf("第二个节点,data,next: %d, %d, %d\r\n",
&tempNode2, &tempNode2.data, &tempNode2.next);
tempNode1.next = &tempNode2;
printf("--------------**********-------------\n\n");
}
int main() {
insertDeleteTest();
insertLocateTest();
basicAddressTest();
return 0;
}