目次
1 はじめに
日付:2023.6.21
書籍: 2024 データ構造 PubMed レビュー ガイド (Wang Dao PubMed シリーズ)
内容:二重リンクリストの実装、構造定義、初期化、新規ノードの作成、先頭挿入・末尾挿入、クエリ、ビット順の挿入、指定ノードの削除、単一リンクリストの出力
2. コードの難しさ
2.1 二重リンクリストの挿入と削除
p ノードの後に s ノードを挿入します。
上図のステートメントのシーケンスは一意ではありませんが、任意でもありません。
手順①と②は手順④の前に行う必要があります。
そうしないと、p の後継ノードのポインタが失われ、挿入が失敗します。
理解を深めるために、読者は紙に模式図を描くことができます。
ここで、①②には順序要件がありません
ので、質問をノードqの先行ノード*pの削除を要求するように変更した場合、具体的な操作手順を考えてください。
3. コード機能
3.1 二重リンクリスト構造定義
#include <stdio.h>
#include <stdlib.h>
//C语言自定义bool操作
#define bool char
#define false 0
#define true 1
/*数据元素类型*/
typedef int ElemType;
/*双链表结构体定义*/
typedef struct DNode //定双链表结点类型
{
ElemType data; //每个结点存放一个数据元素
struct DNode *next; //指针指向下一节点
struct DNode *prior; //指针指向上一节点
}DNode,*DLinkList;
3.2 二重リンクリスト初期化関数
/*双链表初始化函数*/
DLinkList DLinkListInit()
{
//[1]申请空间
DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
//[2]安排指针
L->next = NULL;
L->prior = NULL;
//[3]返回头节点
return L;
}
3.3 二重リンクリストの挿入
/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data){
//[1]为新节点分配空间,并判断是否分配成功
DNode* newNode = (DNode*)malloc(sizeof(DNode));
if(!newNode){
printf("分配空间失败,请检查内存!\n");
return NULL;
}
//[2]初始化新节点
newNode->data = data;
newNode->next = NULL;
newNode->prior = NULL;
//[3]返回节点地址
return newNode;
}
//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i){
//[1]判空
if(L->next == NULL) {printf("这是空表!"); return L;}
//[2]生成指向目标节点的指针p
DNode* p = L->next;
//[3]如果i = 0
if(i < 1){
p = L;
return p;
}
//[4]开始循环定位
while (p->next != NULL && i != 1){
p = p->next;
i--;
}
//[5]返回节点
if(i != 1)
printf("没有这个节点,返回链表的最后一位.\n");
return p;
}
//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e){
//[1]判空
if(L->next == NULL) {printf("这是空表!"); return L;}
//[2]生成指向目标节点的指针p
DNode* p = L->next;
//[3]开始循环定位
while (p->next != NULL && p->data != e){
p = p->next;
}
//[4]返回节点
if(p->data != e)//排除最后一位元素是目标元素的情况
printf("没有这个节点,返回链表的最后一位.");
return p;
}
//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e){
//[0]程序健壮性增强
if(i < 1){
printf("输入出错!");
return 0;
}
//[1]建立新元素节点
DNode* s = CreateNewDNode(e);
if(s == NULL) return 0;
//[2]生成指向待插入位置的指针p
DNode* p = GetElem(L,i-1);
//[3]插入新节点
s->next = p->next;
if(p->next != NULL)
p->next->prior = s;
s->prior = p;
p->next = s;
//[4]插入成功,返回结果
return 1;
}
3.4 二重リンクリストノードの削除
//按位删除
bool DLinkLisDelete(DLinkList L,int i){
//[1]判空
if(L->next == NULL){
printf("表空,无删除元素\n");
return false;
}
//[2]定位,找到待删除元素的前一位*p和待删除元素*q
DNode* p = GetElem(L,i-1);
if(p == NULL) return false;
DNode* q = p->next;
if(q == NULL) return false; //*p没有后继结点
//[3]执行删除操作
p->next = q->next;
if(q->next != NULL) //*q不是最后一位元素
q->next->prior = p;
free(q);
return true;
//没有q的写法
// if(p->next == NULL) false; //最后一位,没有后继
// p->next = p->next->next;
// if(p->next->next != NULL) //待删除结点不是最后一个节点
// p->next->next->prior = p;
// free(p); //释放结点空间
// return true;
}
//删除双链表
void DestoryList(DLinkList L){
while (L->next != NULL){
DLinkLisDelete(L,1);
}
}
3.5 二重リンクリストの走査
/*双链表的遍历*/
int PrintDLinkList(DLinkList L){
//[1]判空
if (L == NULL){
printf("该链表不存在\n");
return 0;
}
if(L->next == NULL){
printf("这是空表!没有需要打印的元素");
return 0;
}
//[2]生成当前要打印的元素位置的指针p
DNode* p = L->next;
//[3]遍历打印
int i = 0;
while (p!= NULL){
i++;
printf("第%d个元素的内容值为:%d\n",i,p->data);
p = p->next;
}
printf("打印结束,共%d个链表结点.\n",i);
return 0;
}
4. コードを完成させます
#include <stdio.h>
#include <stdlib.h>
//C语言自定义bool操作
#define bool char
#define false 0
#define true 1
/*数据元素类型*/
typedef int ElemType;
/*双链表结构体定义*/
typedef struct DNode{ //定双链表结点类型
ElemType data; //每个结点存放一个数据元素
struct DNode *next; //指针指向下一节点
struct DNode *prior; //指针指向上一节点
}DNode,*DLinkList;
/*双链表初始化函数*/
DLinkList DLinkListInit(){
//[1]申请空间
DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
//[2]安排指针
L->next = NULL;
L->prior = NULL;
//[3]返回头节点
return L;
}
/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data){
//[1]为新节点分配空间,并判断是否分配成功
DNode* newNode = (DNode*)malloc(sizeof(DNode));
if(!newNode){
printf("分配空间失败,请检查内存!\n");
return NULL;
}
//[2]初始化新节点
newNode->data = data;
newNode->next = NULL;
newNode->prior = NULL;
//[3]返回节点地址
return newNode;
}
//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i){
//[1]判空
if(L->next == NULL) {printf("这是空表!"); return L;}
//[2]生成指向目标节点的指针p
DNode* p = L->next;
//[3]如果i = 0
if(i < 1){
p = L;
return p;
}
//[4]开始循环定位
while (p->next != NULL && i != 1){
p = p->next;
i--;
}
//[5]返回节点
if(i != 1)
printf("没有这个节点,返回链表的最后一位.\n");
return p;
}
//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e){
//[1]判空
if(L->next == NULL) {printf("这是空表!"); return L;}
//[2]生成指向目标节点的指针p
DNode* p = L->next;
//[3]开始循环定位
while (p->next != NULL && p->data != e){
p = p->next;
}
//[4]返回节点
if(p->data != e)//排除最后一位元素是目标元素的情况
printf("没有这个节点,返回链表的最后一位.");
return p;
}
//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e){
//[0]程序健壮性增强
if(i < 1){
printf("输入出错!");
return 0;
}
//[1]建立新元素节点
DNode* s = CreateNewDNode(e);
if(s == NULL) return 0;
//[2]生成指向待插入位置的指针p
DNode* p = GetElem(L,i-1);
//[3]插入新节点
s->next = p->next;
if(p->next != NULL)
p->next->prior = s;
s->prior = p;
p->next = s;
//[4]插入成功,返回结果
return 1;
}
/*双链表的遍历*/
int PrintDLinkList(DLinkList L){
//[1]判空
if (L == NULL){
printf("该链表不存在\n");
return 0;
}
if(L->next == NULL){
printf("这是空表!没有需要打印的元素");
return 0;
}
//[2]生成当前要打印的元素位置的指针p
DNode* p = L->next;
//[3]遍历打印
int i = 0;
while (p!= NULL){
i++;
printf("第%d个元素的内容值为:%d\n",i,p->data);
p = p->next;
}
printf("打印结束,共%d个链表结点.\n",i);
return 0;
}
/*双链表的删除操作*/
//按位删除
bool DLinkLisDelete(DLinkList L,int i){
//[1]判空
if(L->next == NULL){
printf("表空,无删除元素\n");
return false;
}
//[2]定位,找到待删除元素的前一位*p和待删除元素*q
DNode* p = GetElem(L,i-1);
if(p == NULL) return false;
DNode* q = p->next;
if(q == NULL) return false; //*p没有后继结点
//[3]执行删除操作
p->next = q->next;
if(q->next != NULL) //*q不是最后一位元素
q->next->prior = p;
free(q);
return true;
//没有q的写法
// if(p->next == NULL) false; //最后一位,没有后继
// p->next = p->next->next;
// if(p->next->next != NULL) //待删除结点不是最后一个节点
// p->next->next->prior = p;
// free(p); //释放结点空间
// return true;
}
//删除双链表
void DestoryList(DLinkList L){
while (L->next != NULL){
DLinkLisDelete(L,1);
}
}
int main(){
//[1]不带头结点的声明定义双链表
DLinkList L = NULL;
//[2]带头节点的声明定义双链表
L = DLinkListInit();
//[3]测试:插入结点
DLinkListInsert(L,1,1);
DLinkListInsert(L,1,2);
DLinkListInsert(L,1,3);
DLinkListInsert(L,1,4);
DLinkListInsert(L,1,5);
DLinkListInsert(L,1,6);
DLinkListInsert(L,1,7);
DLinkListInsert(L,1,8);
DLinkListInsert(L,1,9);
DLinkListInsert(L,1,10);
DLinkListInsert(L,1,11);
DLinkListInsert(L,1,12);
PrintDLinkList(L);
DLinkListInsert(L,4,888);
DLinkListInsert(L,7,1022);
DLinkListInsert(L,9,963);
DLinkListInsert(L,11,8522);
DLinkListInsert(L,100,150);
DLinkListInsert(L,4,12000);
DLinkListInsert(L,8,17869);
PrintDLinkList(L);
DLinkLisDelete(L,8);
PrintDLinkList(L);
DestoryList(L);
L = NULL;
PrintDLinkList(L);
// DNode* node = LocateElem(L,150);
// printf("Node.data = %d",node->data);
return 0;
}