【数据结构】速速收藏,一文带你参透双向链表各接口实现

这篇具有很好参考价值的文章主要介绍了【数据结构】速速收藏,一文带你参透双向链表各接口实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

🥕前言🥕:

🌽一、双向链表概述🌽:

1.双向链表概念:

2.双向链表结构:

🍆二、双向链表接口实现🍆:

1.工程文件建立:

2.接口实现(本文重点):

Ⅰ.双向链表初始化:

Ⅱ.打印双向链表:

Ⅲ.申请新节点:

Ⅳ.双向链表尾插:

Ⅴ.双向链表尾删:

Ⅵ.双向链表头插:

Ⅶ.双向链表头删:

Ⅷ.双向链表查找:

Ⅸ.双向链表给定节点前插:

Ⅹ.双向链表给定节点后插:

ⅩⅠ.双向链表删除给定节点:

ⅩⅡ.双向链表销毁:

🍄三、完整接口实现代码🍄:

1.List.h:

2.List.c:

3.test.c:

🌶️四、顺序表与链表对比🌶️:

1.两者差异:

2.存储器层次结构(辅图):

🥬总结🥬:


🛰️博客主页:✈️銮同学的干货分享基地

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:🎈 数据结构

                       🎈【进阶】C语言学习

                       🎈  C语言学习

🛰️代码仓库:🎉数据结构仓库

                       🎉VS2022_C语言仓库

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!


🏡🏡 本文重点 🏡🏡:

🚅 双向链表 🚃 顺序表与链表对比 🚏🚏

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

🥕前言🥕:

        上节课中我们完整的实现了无头单向链表的各个功能接口,但是我们也注意到,由于单向链表只保存指向下一节点的指针,于是我们在进行前插等操作时,还需要遍历链表来找到前一个节点,效率不高且步骤繁琐。于是为了克服类似这样的问题,我们更多的会使用另一种数据结构,即带头双向循环链表,本文就将带领各位小伙伴们一起实现带头双向循环链表的各接口功能

🌽一、双向链表概述🌽:

1.双向链表概念:

        双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

        并且在上节课中我们就说过

  • 无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,哈希桶、图的邻接表等。
  • 带头双向循环链表:结构最复杂,一般用在单独存储数据。虽然它结构复杂,但在实际使用中使用代码实现后,优秀的结构会带来很多优势,实现反而更加简单。并且在我们的实际中所使用的链表数据结构,一般都是带头双向循环链表

         所以今天我们就主要研究带头双向循环链表的各个接口功能的实现

2.双向链表结构:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

🍆二、双向链表接口实现🍆:

1.工程文件建立:

        我们仍使用模块化开发格式,使用 List.h 、List.c 、test.c 三个文件进行代码书写:

  • List.h存放函数声明、包含其他头文件、定义宏
  • List.c书写函数定义,书写函数实现
  • test.c书写程序整体执行逻辑

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

        这其中,我们的接口实现主要研究的是函数实现文件 List.c 中的内容,对 test.c 文件中的内容分不关心

2.接口实现(本文重点):

        这里是本文重点中的重点,即 List.c 文件中的接口具体实现:

Ⅰ.双向链表初始化:

  • 双向链表初始化:
  • 动态申请首节点,并使两个指向直接前置节点与直接后继节点的指针均指向自己,形成循环结构。
  • 最后返回初始化完成的头节点
LNode* LInit()
{
	//哨兵位头节点:
	LNode* phead = (LNode*)molloc(sizeof(LNode));
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

Ⅱ.打印双向链表:

  • 执行操作前需对传入指针进行非空判断,防止对空指针进行操作。 
  • 双向链表的打印方式与单链表相似,采用方式均为由头节点开始,通过节点指针指向寻找下一节点的方式循环进行遍历打印
  • 不同点是,由于双向循环链表首尾相连,形成闭环,因此终止循环打印条件将不再是执行至空指针而是执行回到头节点(即完成整个循环)
void LPrint(LNode* phead)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead)
    {
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("NULL\n");
}

Ⅲ.申请新节点:

  • 新节点的申请与单链表基本相同,动态申请新节点后,再对新节点进行操作。
  • 不同点是双向链表多出一个指向直接前驱节点的指针,因此该指针也需要在使用前进行置空操作,防止造成野指针错误。
LNode* BuyListNode(LDataType x)
{
    LNode* newnode = (LNode*)malloc(sizeof(LNode));
    newnode->data = x;
    newnode->next = NULL;
    newnode->prev = NULL;
    return newnode;
}

Ⅳ.双向链表尾插:

  • 执行操作前应当进行非空判断,防止传入空指针
  • 在进行尾插操作前应当首先找到尾节点,采用的方式是,通过双向循环链表中头节点的前驱指针指向来找到尾节点。
  • 接着动态申请新节点
  • 最后执行尾插操作。首先使前面找到的尾节点的后继指针指向新节点,并使新节点的前驱指针也指向尾节点;接着使头节点的前驱指针指向新节点,并使新节点的后继指针指向头节点
void LPushBack(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* tail = phead->prev;    //找到尾节点
    LNode* newnode = BuyListNode(x);
    //新尾互指:
    tail->next = newnode;
    newnode->prev = tail;
    //新头互指:
    phead->prev = newnode;
    newnode->next = phead;
}
  • 测试尾插接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅴ.双向链表尾删:

  • 在双向链表进行尾删时,不仅要防止传入空指针,同时也要注意避免链表为空(只含有哨兵节点)的情况发生
  • 首先找到尾节点及尾节点的前驱节点,接着使该前驱节点与头节点跳过尾节点互指,最后释放原尾节点并置空即可
void LPopBack(LNode* phead)
{
    if ((phead == NULL) || (phead->next == phead))    //排除为空的情况
    {
        return;
    }
    LNode* tail = phead->prev;    //找到尾
    LNode* tailprev = tail->prev;    //找到尾的前驱
    tailprev->next = phead;    //尾前驱节点的后继指针指向头
    phead->prev = tail->prev;  //头的前驱指针指向尾的前驱
    free(tail);
    tail = NULL;
}
  • 测试尾删接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅵ.双向链表头插:

  • 执行操作前应当对传入指针进行判断,防止传入空指针
  • 在改变指向前,应当首先保存哨兵节点的后继节点,因为当我们插入新节点后链表结构将会发生改变,再想要找到该节点将变得麻烦
  • 进行插入操作时,使哨兵节点的后继指针指向新节点,再使新节点的前驱指针指向哨兵节点,接着使用同样的操作使新节点与哨兵节点的原后继节点互指
void LPushFront(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* newnode = BuyListNode(x);
    LNode* next = phead->next;    //保存哨兵节点的后继节点
    phead->next = newnode;    //哨兵点的后继指针指向新节点
    newnode->prev = phead;    //新节点的前驱指针指向哨兵节点
    newnode->next = next;    //新节点的后继指针指向哨兵节点的原后继节点
    next->prev = newnode;    //哨兵节点的原后继节点前驱指针指向新节点
}
  • 测试头插接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅶ.双向链表头删:

  • 首先进行非空判断,并排除链表为空(只含有哨兵节点)的情况。
  • 开始进行头删操作前找到并保存头节点,防止改变指向后链表结构发生变化难以找到原本的头节点,以便于最后进行释放
  • 并且应当找到并保存原头节点的后继节点,防止防止改变指向后链表结构发生变化而难以找到
  • 具体操作便是使哨兵节点与头节点的后继节点跳过头节点互指,再将要删除的头节点释放并置空即可。
void LPopFront(LNode* phead)
{
    if ((phead == NULL) || (phead->next == phead))    //排除为空的情况
    {
        return;
    }
    LNode* next = phead->next;    //保存头节点,便于释放
    LNode* nextNext = next->next;    //保存头节点的后继节点
    phead->next = nextNext;
    nextNext->prev = phead;
    free(next);
    next = NULL;
}
  • 测试头删接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅷ.双向链表查找:

  • 执行操作前需进行非空判断,防止对空指针进行操作。
  • 查找逻辑很简单,遍历整个链表,直至链表完整循环一遍,若比对存在匹配元素返回该节点,否则返回空。
LNode* LFind(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead)
    {
        if (cur->data == x)
        {
            return cur;
        }
        else
        {
            cur = cur->next;
        }
    }
    return NULL;
}
  • 测试查找接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅸ.双向链表给定节点前插:

  • 执行操作前需进行非空判断,防止对空指针进行操作。
  • 执行逻辑很简单,将数据存入通过动态申请的来的新节点中后,找到目标节点,使目标节点的前驱节点与新节点互指,再使新节点与目标节点互指接即可。
void LInsert(LNode* pos, LDataType x)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->prev;
    LNode* newnode = BuyListNode(x);
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
}
  • 测试前插接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

Ⅹ.双向链表给定节点后插:

  • 执行操作前需进行非空判断,防止对空指针进行操作。
  • 执行逻辑与前插高度类似,不同的是使目标节点的后继节点与新节点互指,再使新节点与目标节点互指
void LInsertBack(LNode* pos, LDataType x)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->next;
    LNode* newnode = BuyListNode(x);
    posPrev->prev = newnode;
    newnode->next = posPrev;
    newnode->prev = pos;
    pos->next = newnode;
}
  • 测试后插接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

ⅩⅠ.双向链表删除给定节点:

  • 执行操作前需进行非空判断,防止操作空指针。
void LErase(LNode* pos)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->prev;
    LNode* posNext = pos->next;
    posPrev->next = posNext;
    posNext->prev = posPrev;
    free(pos);
    pos = NULL;
}
  • 测试删除接口功能实现:

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

ⅩⅡ.双向链表销毁:

  • 哨兵节点为空,即表示链表内没有有效数据节点,则无需进行销毁、释放与置空操作
  • 含有有效节点则遍历所有节点,将每一个节点均进行释放,特别注意所有数据节点释放完毕之后,不要忘记释放哨兵节点
void LDestroy(LNode* phead)
{
    if(phead==NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead);
    {
        LNode* next = cur->next;
        free(cur);
        cur = next;
    }
    free(phead);
    phead = NULL;
}

🍄三、完整接口实现代码🍄:

1.List.h:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//自定数据类型LDataType:
typedef int LDataType;

//双向链表节点结构:
typedef struct ListNode
{
	LDataType data;
	struct LNode* next;
	struct LNode* prev;
}LNode;

LNode* LInit();    //初始化双向循环链表
void LPrint(LNode* phead);    //打印双向循环链表
LNode* BuyListNode(LDataType x);//双向循环链表新节点申请
void LPushBack(LNode* phead, LDataType x);    //双向循环链表尾插
void LPopBack(LNode* phead);    //双向循环链表尾删
void LPushFront(LNode* phead, LDataType x);    //双向循环链表头插
void LPopFront(LNode* phead);    //双向循环链表头删
LNode* LFind(LNode* phead, LDataType x);    //双向循环链表查找
void LInsertFront(LNode* pos, LDataType x);    //双向循环链表给定节点前插
void LInsertBack(LNode* pos, LDataType x);    //双向循环链表给定节点后插
void LErase(LNode* pos);    //双向循环链表给定节点删除
void LDestroy(LNode* phead);    //双向循环链表的销毁

2.List.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include"List.h"

//初始化双向循环链表初始化:
LNode* LInit()
{
	//哨兵位头节点:
	LNode* phead = (LNode*)malloc(sizeof(LNode));
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

//打印双向循环链表
void LPrint(LNode* phead)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead)
    {
        printf("%d -> ", cur->data);
        cur = cur->next;
    }
    printf("NULL\n");
}

//双向循环链表申请新节点:
LNode* BuyListNode(LDataType x)
{
    LNode* newnode = (LNode*)malloc(sizeof(LNode));
    newnode->data = x;
    newnode->next = NULL;
    newnode->prev = NULL;
    return newnode;
}

//双向循环链表尾插:
void LPushBack(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* tail = phead->prev;    //找到尾节点
    LNode* newnode = BuyListNode(x);
    //新尾互指:
    tail->next = newnode;
    newnode->prev = tail;
    //新头互指:
    phead->prev = newnode;
    newnode->next = phead;
}

//双向循环链表尾删:
void LPopBack(LNode* phead)
{
    if ((phead == NULL) || (phead->next == phead))    //排除为空的情况
    {
        return;
    }
    LNode* tail = phead->prev;    //找到尾
    LNode* tailprev = tail->prev;    //找到尾的前驱
    tailprev->next = phead;    //尾前驱节点的后继指针指向头
    phead->prev = tail->prev;  //头的前驱指针指向尾的前驱
    free(tail);
    tail = NULL;
}

//双向循环链表头插:
void LPushFront(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* newnode = BuyListNode(x);
    LNode* next = phead->next;    //保存哨兵节点的后继节点
    phead->next = newnode;    //哨兵点的后继指针指向新节点
    newnode->prev = phead;    //新节点的前驱指针指向哨兵节点
    newnode->next = next;    //新节点的后继指针指向哨兵节点的原后继节点
    next->prev = newnode;    //哨兵节点的原后继节点前驱指针指向新节点
}

//双向循环链表头删:
void LPopFront(LNode* phead)
{
    if ((phead == NULL) || (phead->next == phead))    //排除为空的情况
    {
        return;
    }
    LNode* next = phead->next;    //保存头节点,便于释放
    LNode* nextNext = next->next;    //保存头节点的后继节点
    phead->next = nextNext;
    nextNext->prev = phead;
    free(next);
    next = NULL;
}

//双向循环链表查找:
LNode* LFind(LNode* phead, LDataType x)
{
    if (phead == NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead)
    {
        if (cur->data == x)
        {
            return cur;
        }
        else
        {
            cur = cur->next;
        }
    }
    return NULL;
}

//双向循环链表给定节点前插:
void LInsert(LNode* pos, LDataType x)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->prev;
    LNode* newnode = BuyListNode(x);
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
}

//双向循环链表给定节点前插:
void LInsertFront(LNode* pos, LDataType x)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->prev;
    LNode* newnode = BuyListNode(x);
    posPrev->next = newnode;
    newnode->prev = posPrev;
    newnode->next = pos;
    pos->prev = newnode;
}

//双向循环链表给定节点后插:
void LInsertBack(LNode* pos, LDataType x)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->next;
    LNode* newnode = BuyListNode(x);
    posPrev->prev = newnode;
    newnode->next = posPrev;
    newnode->prev = pos;
    pos->next = newnode;
}

//双向循环链表给定节点删除:
void LErase(LNode* pos)
{
    if (pos == NULL)
    {
        return;
    }
    LNode* posPrev = pos->prev;
    LNode* posNext = pos->next;
    posPrev->next = posNext;
    posNext->prev = posPrev;
    free(pos);
    pos = NULL;
}

//双向循环链表销毁:
void LDestroy(LNode* phead)
{
    if(phead==NULL)
    {
        return;
    }
    LNode* cur = phead->next;
    while (cur != phead);
    {
        LNode* next = cur->next;
        free(cur);
        cur = next;
    }
    free(phead);
    phead = NULL;
}

3.test.c:

#define _CRT_SECURE_NO_WARNINGS 1

#include"List.h"

void LTest()
{
	LNode* plist = LInit();
	//双向循环链表尾插:
	LPushBack(plist, 1);
	LPushBack(plist, 2);
	LPushBack(plist, 3);
	LPushBack(plist, 4);
	LPrint(plist);    //打印链表
	LNode* ret = LFind(plist, 3);
	LErase(ret);
	LPrint(plist);    //打印链表
}

int main()
{
	LTest();

	return 0;
}

//双向循环链表尾插与尾删:
//LNode* plist = LInit();
双向循环链表尾插:
//LPushBack(plist, 1);
//LPushBack(plist, 2);
//LPushBack(plist, 3);
//LPushBack(plist, 4);
//LPrint(plist);    //打印链表
双向循环链表尾删:
//LPopBack(plist);
//LPopBack(plist);
//LPopBack(plist);
//LPrint(plist);    //打印链表

//双向循环链表头插与头删:
//LNode* plist = LInit();
//双向循环链表头插:
//LPushFront(plist, 1);
//LPushFront(plist, 2);
//LPushFront(plist, 3);
//LPushFront(plist, 4);
//LPrint(plist);    //打印链表
双向循环链表头删:
//LPopFront(plist);
//LPopFront(plist);
//LPopFront(plist);
//LPrint(plist);    //打印链表

//双向循环链表查找:
//LNode* plist = LInit();
//双向循环链表尾插:
//LPushBack(plist, 1);
//LPushBack(plist, 2);
//LPushBack(plist, 3);
//LPushBack(plist, 4);
//LPrint(plist);    //打印链表
//LNode* ret = LFind(plist, 3);

//双向循环链表给定位置前插:
//LNode* plist = LInit();
双向循环链表尾插:
//LPushBack(plist, 1);
//LPushBack(plist, 2);
//LPushBack(plist, 3);
//LPushBack(plist, 4);
//LPrint(plist);    //打印链表
//LNode* ret = LFind(plist, 3);
//LInsertFront(ret, 5);
//LPrint(plist);    //打印链表

//双向循环链表给定位置后插:
//LNode* plist = LInit();
双向循环链表尾插:
//LPushBack(plist, 1);
//LPushBack(plist, 2);
//LPushBack(plist, 3);
//LPushBack(plist, 4);
//LPrint(plist);    //打印链表
//LNode* ret = LFind(plist, 3);
//LInsertBack(ret, 5);
//LPrint(plist);    //打印链表

//双向循环链表给定节点删除:
//LNode* plist = LInit();
双向循环链表尾插:
//LPushBack(plist, 1);
//LPushBack(plist, 2);
//LPushBack(plist, 3);
//LPushBack(plist, 4);
//LPrint(plist);    //打印链表
//LNode* ret = LFind(plist, 3);
//LErase(ret);
//LPrint(plist);    //打印链表

🌶️四、顺序表与链表对比🌶️:

1.两者差异:

不同点 顺序表 链   表
连续性 物理上一定连续 逻辑上一定连续
是否支持随机访问
任意位置节点修改 可能需要搬移元素,效率低 只需改变指针指向,效率高
插入方式 动态顺序表,使用时需扩容 无容量概念
应用场景 数据高效存储+频繁访问 节点及数据修改频繁
缓存利用率

2.存储器层次结构(部分差异成因辅图):

使用双向链表实现数据接收的方法,数据结构,数据结构,gitee,算法,c语言,c++

🥬总结🥬:

        至此我们关于带头双向循环链表,乃至链表全部内容的学习和讲解就到此为止喽~不知道各位小伙伴们掌握了多少呢?希望各位小伙伴们下去以后多加练习,夯实基础,牢固掌握链表与顺序表的相关接口实现与使用,为后面的 C++ 高阶数据结构学习打好坚实的基础!!!

        🔥🔥相信自己拥有无限的潜力,只要你有一刻渴望成长,它就会支撑着你开花结果🔥🔥

        更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~  你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!文章来源地址https://www.toymoban.com/news/detail-783185.html

到了这里,关于【数据结构】速速收藏,一文带你参透双向链表各接口实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】一文带你全面了解排序(上)——直接插入排序、希尔排序、选择排序、堆排序

    目录 一、排序的概念及其运用 1.1 排序的概念 1.2 常见的算法排序 二、常见排序算法的实现 2.1 插入排序 2.1.1 思想 2.1.2 直接插入排序 2.1.3 希尔排序(缩小增量排序)  2.2 选择排序 2.2.1 基本思想 2.2.2 直接选择排序 2.2.3 堆排序  没有坚持的努力实质上并没有太大的意义

    2024年02月16日
    浏览(55)
  • 最最最全数据仓库建设指南,速速收藏!

    开讲之前,我们先来回顾一下数据仓库的定义。 数据仓库(Data Warehouse)是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策。这个概念最早由数据仓库之父比尔·恩门(Bill Inmon)于1990年在《建立数据仓库》一书中提出,近年来却被愈发广泛的

    2024年03月20日
    浏览(39)
  • 目标检测算法——图像去噪开源数据集汇总(速速收藏)

    数据集下载地址:https://sourl.cn/jdpJZ6 该数据集包含以下智能手机在不同光照条件下拍摄的 160 对噪声/真实图像: GP: Google Pixel  IP: iPhone 7  S6: Samsung Galaxy S6  Edge N6: Motorola Nexus 6  G4: LG G4 数据集下载地址:https://sourl.cn/kaYGxd 一个小型版本的数据集,它由代表 160 个场景实例的

    2024年02月10日
    浏览(42)
  • 目标检测算法——图像去雾开源数据集汇总(速速收藏)

    下载地址:http://m6z.cn/5IBauH RESIDE数据集包括合成和真实世界的模糊图像,称为REalistic Single Image Dehazing,RESIDE突出显示了各种数据源和图像内容,并分为五个子集,每个子集用于不同的训练或评估目的。提供了各种各样的去雾算法评估标准,从完整参考度量,无参考度量,到主

    2024年02月06日
    浏览(43)
  • 【数据结构】带你深入理解栈

    栈是一种特殊的线性表。其只允许在固定的一端进行插入和删除元素的操作,进行数据的插入和删除的一端称作 栈顶 ,另外一端称作 栈底 。 栈不支持随机访问 ,栈的数据元素遵循 后进先出 的原则,即 LIFO(Late In First Out)。 也许有人曾经听说过 压栈 和 入栈 的术语,以

    2024年02月03日
    浏览(43)
  • 深度剖析Redis九种数据结构实现原理,建议收藏

    Redis 是一个高性能的键值存储系统,支持多种数据结构。 包含五种基本类型 String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(有序集合),和三种特殊类型 Geo(地理位置)、HyperLogLog(基数统计)、Bitmaps(位图)。 每种数据结构都是为了解决特定问题而设计

    2023年04月11日
    浏览(41)
  • 【数据结构】一篇带你彻底了解栈

    栈:一种线性数据结构,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶 (Top), 另一端称为栈底 [Bottom]。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。即最后进入的元素最先被访问。 压栈:栈的插入操作叫做进栈/压栈

    2024年02月05日
    浏览(88)
  • 【数据结构】一篇带你彻底吃透 顺序表

    顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改等功能。 顺序表一般可以分为: 静态顺序表:使用定长数组存储元素。 动态顺序表:使用动态开辟的数组存储。 而现实的顺序表大多数采用动态

    2023年04月19日
    浏览(81)
  • 【数据结构】带你轻松拿捏顺序表(内附源码)

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,米娜桑们,这里是君兮_,今天正式开始开新坑啦!在接下来的这一个月来我会逐步带大家了解初阶数据结构的知识,如果是你主修的是计算机专业数据结构的重要性不言而喻,哪怕在以后你工作面试时,它也是面试

    2024年02月15日
    浏览(44)
  • 深入浅出带你玩转栈与队列——【数据结构】

    W...Y的主页 😊 代码仓库分享 💕 目录 1.栈 1.1栈的概念及结构 1.2栈的结构特征图  ​编辑 1.3栈的实现 1.3.1栈的初始化 1.3.2进栈 1.3.3出栈 1.3.4销毁内存 1.3.5判断栈是否为空 1.3.5栈底元素的读取 1.3.6栈中大小 1.4栈实现所有接口 2.队列 2.1队列的概念 2.2队列的结构   2.3队列的实

    2024年02月11日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包