草庐IT

考研数据结构模板:顺序表、链表、栈、队列

珂霖 2023-07-16 原文

考研数据结构模板:顺序表、链表、栈、队列

前言

  1. 代码风格偏向于考研风格而非算法竞赛风格。
  2. 代码实现参考《2024数据结构王道复习指导》。
  3. 注释详细、保证看懂。
  4. 下面是已实现的数据结构模板:
    1. 顺序表SeqList
    2. 链表LinkList
    3. 双链表DLinkList
    4. 顺序栈SeqStack
    5. 循环顺序队列CircleQueue
    6. 链队列LinkQueue

顺序表SeqList

顺序表定义

// 定义顺序表
struct SeqList {
    int *data; // 数据动态分配
    int length, maxLength; // 当前长度、最大长度
};
// 最大容量
#define SEQ_LIST_MAX_SIZE 100
// 初始容量
#define SQL_LIST_INIT_SIZE 10

初始化

void SeqListInitial(SeqList &list) {
    list.maxLength = SQL_LIST_INIT_SIZE;
    list.data = new int[list.maxLength];
    list.length = 0;
}

判断是否为空

bool SeqListIsEmpty(SeqList &list) {
    return list.length == 0;
}

查询元素长度

int SeqListLength(SeqList &list) {
    return list.length;
}

打印元素

void SeqListPrint(SeqList &list) {
    for (int i = 0; i < list.length; i++) {
        printf("%d ", list.data[i]);
    }
}

插入元素

bool SeqListInsert(SeqList &list, int index, int data) {
    if (index < 1 || index > list.length + 1) { // index范围必须在[1, list.SeqListLength + 1]
        return false; // 下标溢出
    }
    if (list.length == list.maxLength) { // 空间不足,申请空间
        if (list.length == SEQ_LIST_MAX_SIZE) {
            return false; // 空间溢出
        } else {
            int maxLength; // 下一次申请空间的长度
            if (list.length * 2 < SEQ_LIST_MAX_SIZE) {
                maxLength = list.length * 2; // 容量每次扩大两倍
            } else {
                maxLength = SEQ_LIST_MAX_SIZE;
            }
            int *memory = new int[maxLength]; // 创建一块存储空间
            for (int i = 0; i < list.length; i++) { // 复制数组
                memory[i] = list.data[i];
            }
            delete list.data; // 释放原来的空间
            list.data = memory;
            list.maxLength = maxLength;
        }
    }
    for (int i = list.length; i >= index; i--) { // 移动数组
        list.data[i] = list.data[i - 1];
    }
    list.length++;
    list.data[index - 1] = data; // 插入元素
    return true;
}

删除元素

bool SeqListRemove(SeqList &list, int index, int &data) {
    if (index < 1 || index > list.length) { // index取值范围为[1, list.SeqListLength]
        return false; // 溢出
    }
    data = list.data[index - 1]; // 保存删除的数据
    for (int i = index; i < list.length; i++) { // 移动元素
        list.data[i - 1] = list.data[i];
    }
    list.length--;
    return true;
}

查询元素位置

int SeqListFindIndex(SeqList &list, int data) {
    for (int i = 0; i < list.length; i++) { // 遍历数组
        if (list.data[i] == data) {
            return i + 1;
        }
    }
    return -1; // 找不到则返回-1
}

查询位置上的元素值

bool SeqListGet(SeqList &list, int index, int &data) {
    if (index < 1 || index > list.length) { // 下标范围在[1, list.length]之间
        return false;
    }
    data = list.data[index - 1]; // 保存元素
    return true;
}

链表定义

// 单链表节点
struct LinkListNode {
    int data;
    LinkListNode *next;
};

// 单链表
struct LinkList {
    LinkListNode *head; // 头指针
    LinkListNode *tail; // 尾指针
};

空元素初始化

void LinkListInitial(LinkList &list) {
    LinkListNode *node = new LinkListNode(); // 初始化头节点
    list.head = node;
    list.tail = node;
}

数组初始化

void LinkListInitial(LinkList &list, int data[], int length) {
    LinkListNode *node = new LinkListNode();
    list.head = node;
    list.tail = node;
    for (int i = 0; i < length; i++) { // 尾插法插入所有元素
        LinkListNode *next = new LinkListNode();
        next->data = data[i];
        list.tail->next = next;
        list.tail = list.tail->next;
    }
}

查询元素长度

int LinkListLength(LinkList &list) {
    int length = 0;
    LinkListNode *p = list.head->next;
    while (p != NULL) { // 遍历链表直到为空
        length++;
        p = p->next;
    }
    return length;
}

打印元素

void LinkListPrint(LinkList &list) {
    if (list.head == list.tail) {
        return;
    }
    LinkListNode *p = list.head->next;
    while (p != NULL) { // 遍历所有元素,直到为空
        printf("%d ", p->data);
        p = p->next;
    }
}

插入元素

bool LinkListInsert(LinkList &list, int index, int data) {
    if (index < 1) { // 下标范围必须大于等于1
        return false;
    }
    LinkListNode *p = list.head; // 用于保存插入位置的前驱
    for (int i = 1; i < index; i++) { // 找到插入位置的前驱
        p = p->next;
        if (p == NULL) {
            return false; // 不存在此下标
        }
    }
    LinkListNode *node = new LinkListNode(); // 插入元素
    node->data = data;
    node->next = p->next;
    p->next = node;
    return true;
}

删除元素

bool LinkListRemove(LinkList &list, int index, int &data) {
    if (index < 1) { // 下标范围必须大于等于1
        return false;
    }
    LinkListNode *p = list.head; // 用于保存插入位置的前驱
    for (int i = 1; i < index; i++) { // 查找删除位置的前驱
        p = p->next;
        if (p == NULL) {
            return false; // 不存在此下标
        }
    }
    LinkListNode *node = p->next; // 执行删除操作
    data = node->data; // 保存删除节点的值
    p->next = node->next;
    delete node; // 释放空间
    return true;
}

查询位置上的元素值

bool LinkListGet(LinkList &list, int index, int &data) {
    if (index < 1) { // 下标范围必须大于等于1
        return false;
    }
    LinkListNode *p = list.head;
    for (int i = 1; i <= index; i++) { // 遍历链表
        p = p->next;
        if (p == NULL) {
            return false; // 不存在此下标
        }
    }
    data = p->data;
    return true;
}

双链表定义

// 双链表节点
struct DLinkListNode {
    int data;
    DLinkListNode *prev, *next; // 前驱与后继节点
};

// 双链表
struct DLinkList {
    DLinkListNode *head; // 头节点
};

初始化

void DLinkListInitial(DLinkList &list) {
    DLinkListNode *head = new DLinkListNode(); // 创建头节点
    list.head = head;
}

打印元素

void DLinkListPrint(DLinkList &list) {
    DLinkListNode *p = list.head;
    while (p->next != NULL) {
        p = p->next;
        printf("%d ", p->data);
    }
}

插入元素

bool DLinkListNodeInsert(DLinkList &list, int index, int data) {
    if (index < 1) { // 下标范围必须大于等于1
        return false;
    }
    DLinkListNode *p = list.head;
    for (int i = 1; i < index; i++) { // 找到插入位置的前驱
        p = p->next;
        if (p == NULL) {
            return false; // 不存在此下标
        }
    }
    DLinkListNode *node = new DLinkListNode(); // 插入元素
    node->data = data;
    node->next = p->next;
    if (p->next != NULL) {
        p->next->prev = node;
    }
    node->prev = p;
    p->next = node;
    return true;
}

删除元素

bool DLinkListRemove(DLinkList &list, int index) {
    if (index < 1) { // 下标范围必须大于等于1
        return false;
    }
    DLinkListNode *p = list.head; // 找到删除位置的前驱
    for (int i = 1; i < index; i++) {
        p = p->next;
        if (p == NULL) {
            return false; // 不存在此下标
        }
    }
    DLinkListNode *q = p->next; // 被删除的元素
    if (q == NULL) { // 当q为链表末尾时,则被删除的元素不存在
        return false;
    }
    p->next = q->next;
    if (q->next != NULL) {
        q->next->prev = p;
    }
    delete q; // 释放空间
    return true;
}

顺序栈SeqStack

顺序栈定义

// 最大空间
#define SEQ_STACK_MAX_SIZE 100

// 顺序栈
struct SeqStack {
    int data[SEQ_STACK_MAX_SIZE];
    int top; // 栈顶指针
};

初始化

void SeqStackInitStack(SeqStack &stack) {
    stack.top = -1; // 使用-1标识为空栈
}

判断是否为空

bool SeqStackIsEmpty(SeqStack &stack) {
    return stack.top == -1;
}

进栈

bool SeqStackPush(SeqStack &stack, int data) {
    if (stack.top == SEQ_STACK_MAX_SIZE - 1) {
        return false; // 空间不够
    }
    stack.data[++stack.top] = data; // 指针后移并添加元素
    return true;
}

出栈

bool SeqStackPop(SeqStack &stack, int &data) {
    if (stack.top == -1) {
        return false; // 没有元素
    }
    data = stack.data[stack.top--]; // 删除元素并将指针前移
    return true;
}

读取栈顶元素

bool SeqStackGetTop(SeqStack &stack, int &data) {
    if (stack.top == -1) {
        return false; // 没有元素
    }
    data = stack.data[stack.top];
    return true;
}

循环顺序队列CircleQueue

循环顺序队列定义

// 最大空间
#define CIRCLE_QUEUE_MAX_SIZE 10

// 循环顺序队列
struct CircleQueue {
    int data[CIRCLE_QUEUE_MAX_SIZE];
    int front, rear; // 头指针和尾指针
};

初始化

void CircleQueueInit(CircleQueue &queue) {
    queue.front = queue.rear = 0;
}

判断队列是否为空

bool CircleQueueIsEmpty(CircleQueue &queue) {
    return queue.front == queue.rear;
}

判断队列是否已满

bool CircleQueueIsFull(CircleQueue &queue) {
    return (queue.rear + 1) % CIRCLE_QUEUE_MAX_SIZE == queue.front; // 队尾的下一个位置是队头,则说明队满
}

获取队列长度

int CircleQueueLength(CircleQueue &queue) {
    return (queue.rear - queue.front + CIRCLE_QUEUE_MAX_SIZE) % CIRCLE_QUEUE_MAX_SIZE;
}

进队

bool CircleQueuePush(CircleQueue &queue, int data) {
    if (CircleQueueIsFull(queue)) { // 如果队列已满,则无法进队
        return false;
    }
    queue.data[(queue.rear++) % CIRCLE_QUEUE_MAX_SIZE] = data; // 取模实现循环
    return true;
}

出队

bool CircleQueuePop(CircleQueue &queue, int &data) {
    if (CircleQueueIsEmpty(queue)) { // 如果队列为空,则无法出队
        return false;
    }
    data = queue.data[(queue.front++) % CIRCLE_QUEUE_MAX_SIZE];
    return true;
}

链队列LinkQueue

链队列定义

// 链队列节点
struct LinkQueueNode {
    int data;
    LinkQueueNode *next;
};

// 链队列
struct LinkQueue {
    LinkQueueNode *front, *rear; // 头指针和尾指针
};

初始化

void LinkQueueInit(LinkQueue &queue) {
    LinkQueueNode *head = new LinkQueueNode(); // 头节点
    queue.front = queue.rear = head;
}

判断队列是否为空

bool LinkQueueIsEmpty(LinkQueue &queue) {
    return queue.front == queue.rear;
}

获取队列长度

int LinkQueueLength(LinkQueue &queue) {
    int length = 0;
    // 遍历链表直到为空
    LinkQueueNode *p = queue.front->next;
    while (p != NULL) {
        length++;
        p = p->next;
    }
    return length;
}

进队

void LinkQueuePush(LinkQueue &queue, int data) {
    LinkQueueNode *node = new LinkQueueNode(); // 头节点
    node->data = data;
    queue.rear->next = node;
    queue.rear = queue.rear->next;
}

出队

bool LinkQueuePop(LinkQueue &queue, int &data) {
    if (LinkQueueIsEmpty(queue)) {
        return false; // 队列为空
    }
    LinkQueueNode *head = queue.front; // 头节点
    LinkQueueNode *node = head->next;
    data = node->data;
    queue.front = node; // 新的头节点
    delete head; // 释放空间
    return true;
}

有关考研数据结构模板:顺序表、链表、栈、队列的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  4. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  5. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  6. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  7. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  8. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  9. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  10. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

随机推荐