要約と考察:
1. 利点:シングルリンクリストと比較して、ダブルリンクリストは逆方向にトラバースする機能があり、各ノードが連動しています。
2. 欠点:単一リンクリストと比較して、より多くの操作があり、*previous は前のノードを指す必要があるため、構造体には前のノードへのポインタも含まれるため、より多くのスペースが必要になります。
3.私の提案は、単一のリンクされたリストで十分であるということです
学習目標:
二重リンク リストを学習します。主な目的は、リンク リストのバリエーションを練習し、より多くのデザイン感覚を見つけることです。このようにして、実際的な問題に直面したときに、ある程度のモデリング能力を身につけることができます。
学習ガイド:ファンシェンのコード
学習課題:
- コードをコピーします。
- 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;
}