요약 및 반성:
1. 장점: 단일 연결 리스트와 비교하여 이중 연결 리스트는 역방향 순회 기능을 제공하며 각 노드는 연동
2. 단점: 단일 연결 목록에 비해 연산이 더 많고 *previous가 이전 노드를 가리켜야 하므로 구조도 이전 노드에 대한 포인터를 가지므로 더 많은 공간을 차지합니다.
3. 내 제안은 단일 연결 목록이면 충분하다는 것입니다.
학습 목표:
이중 연결 목록을 배우십시오 주요 목적은 연결 목록의 변형을 연습하고 더 많은 디자인 감각을 찾는 것이므로 실제 문제에 직면했을 때 일정한 모델링 능력을 갖게 될 것입니다.
학습 가이드: Fanshen의 코드
학습 작업:
- 코드를 복사합니다.
- insertElement와 같은 기능에 대해 추가 테스트를 수행합니다.
- locateElement 함수를 직접 구현하십시오.
- 버그를 선택하고 Fanshen Code에 메시지를 남겨주세요.
- CSDN 블로그 작성 도구로 그리거나 사진을 찍을 수 있는 손으로 그린 아이콘이 있어야 합니다.
학습 결과 카탈로그
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;
}