数据结构三个典型的类型整理

检查内存泄漏:

执行命令:valgrinid ./a.out

检查 malloc 和free, 的次数。

GDB

linux 软件开放人员,必须会的4个工具

gcc 编译器 把源文件转换为可执行程序

vim linux 下文本编辑器。

gdb 调试器,检查程序的逻辑错误

makefile 工程管理工具

gdb的常用命令

调试的步骤

gdb 一般调试

  1. 编译自己代码的时候假如调试选择 -g 给a.out 假如调试信息

gcc -g 1.c

具体操作使用:

顺序表和链表 优缺点

存储方式:

顺序表是一段连续的存储单元。

链表是逻辑结构连续物理结构(在内存中的表现形式)不连续。

时间性能:

查找 顺序表O(1)

链表 O(n)

插入和删除 :

顺序表 O(n)

链表 O(1)

空间性能:

顺序表 需要预先分配空间,大小固定。

链表, 不需要预先分配,大小可变,动态分配。

顺序表的主要函数;

bash 复制代码
#include "seqlist.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>





/**
 * @brief 创建一个线性顺序表
 *
 * @param len 顺序表的容量
 * @return SeqList* 返回顺表表头指针
            如果失败返回 NULL
 */
SeqList *CreateSeqList(int len)
{
    //创建表头
    SeqList *sq = malloc(sizeof(SeqList));
    if (NULL == sq)
    {
        printf("CreateSeqList malloc1 error\n");
        return NULL;
    }
    sq->head = malloc(sizeof(DATATYPE) * len);
    if (NULL == sq->head)
    {
        printf("CreateSeqList malloc2 error\n");
        return NULL;
    }
    sq->tlen = len;
    sq->clen = 0;
    return sq;
}







int ShowSeqList(SeqList *list)
{
    int len = GetSizeSeqList(list);
    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("name:%s age:%d sex:%c,score:%d\n", list->head[i].name,
               list->head[i].age, list->head[i].sex, list->head[i].score);
    }
}








/**
 * @brief 尾增数据元素
 *
 * @param list 需要被操作的顺序表的指针
 * @param data 需要新增的数据的指针
 * @return int 0 表示成功  1表示失败
 */
int InsertTailSeqList(SeqList *list, DATATYPE *data)
{
    if (IsFullSeqList(list))
    {
        printf("list is full\n");
        return 1;
    }
    memcpy(&list->head[list->clen], data, sizeof(DATATYPE));
    list->clen++;
    return 0;
}








int IsFullSeqList(SeqList *list)
{
    return list->clen == list->tlen;
}
int IsEmptySeqList(SeqList *list)
{
    return 0 == list->clen;
}






/**
 * @brief 按位置插入元素
 *
 * @param list 待操作的顺序表表头指针
 * @param data 指向待插入顺序表的数据的指针
 * @param pos 需要插入位置 的下标
 * @return int 0 表示成功 1失败,表满  2 pos 不合适
 */
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)
{
    if (IsFullSeqList(list))
    {
        printf("list is full");
        return 1;
    }
    int len = GetSizeSeqList(list);
    if (pos < 0 || pos > len)
    {
        printf("pos error\n");
        return 2;
    }
    int i = 0;
    //整体的下移
    for (i = list->clen - 1; i >= pos; i--)
    {
        // list->head[i+1]=list->head[i];
        memcpy(&list->head[i + 1], &list->head[i], sizeof(DATATYPE));
    }
    memcpy(&list->head[pos], data, sizeof(DATATYPE));
    list->clen++;
    return 0;
}








/**
 * @brief 根据名字查找 人员
 *
 * @param list 待操作的顺序表的指针
 * @param name 需要查找的人名
 * @return int -1 表示失败 >=0 找到的下标
 */
int FindSeqList(SeqList *list, char *name)
{
    if (IsEmptySeqList(list))
    {
        return -1;
    }
    int len = GetSizeSeqList(list);
    int i = 0;
    for (i = 0; i < len; i++)
    {
        if (0 == strcmp(name, list->head[i].name))
        {
            return i;
        }
    }
    return -1;
}









/**
 * @brief 根据名字修改一个人的信息
 *
 * @param list  待操作的顺序表的指针
 * @param oldname 需要被修改的人名
 * @param newdata 替换旧人员的信息
 * @return int 0 成功 1 失败
 */
int ModifySeqList(SeqList *list, char *oldname, DATATYPE *newdata)
{
    int ret = FindSeqList(list, oldname);
    if (-1 == ret)
    {
        printf("modify error\n");
        return 1;
    }

    // list->head[ret] = *newdata;
    memcpy(&list->head[ret], newdata, sizeof(DATATYPE));
    return 0;
}









/**
 * @brief  在顺序表中 根据名字删除一个人
 *
 * @param list  待操作的顺序表的指针
 * @param name 需要被删除的人名
 * @return int 0 表示成功  1失败
 */

####  面试常考 !!!
int DeleteSeqList(SeqList *list, char *name)
{
    int ret = FindSeqList(list, name);
    if (-1 == ret)
    {
        printf("del error\n");
        return 1;
    }
    int len = GetSizeSeqList(list);
    int i = 0;
    for (i = ret; i < len - 1; i++)
    {
        // list->head[i] = list->head[i + 1];
        memcpy(&list->head[i], &list->head[i + 1], sizeof(DATATYPE));
    }
    list->clen--;
    return 0;
}










/**
 * @brief 清空顺序表
 *
 * @param list  待操作的顺序表的指针
 * @return int 0
 */
int ClearSeqList(SeqList *list)
{
    list->clen = 0;
    return 0;
}







/**
 * @brief  获得顺序表,有效元素的个数
 *
 * @param list  需要被操作的顺序表的指针
 * @return int  >=0  返回的是元素的个数
 */
int GetSizeSeqList(SeqList *list)
{
    return list->clen;
}







int DestroySeqList(SeqList *list)
{
    free(list->head);  //释放数组
    free(list);        //释放表头
    return 0;
}

单项链表的函数:

bash 复制代码
#include "linklist.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>




/**
 * @brief Create a Link List object 创建一个单向链表头结构
 *
 * @return LinkList* 指向单向链表表头结构的指针
 */
LinkList *CreateLinkList()
{
    LinkList *ll = malloc(sizeof(LinkList));
    if (NULL == ll)
    {
        printf("CreateLinkList malloc error\n");
        return NULL;
    }

    ll->head = NULL;
    ll->clen = 0;
   return ll;
}









/**
 * @brief 单向链表的头插操作
 *
 * @param list 待操作的链表
 * @param data  需要新增的数据
 * @return int 0 成功 1 失败
 */
int InsertHeadLinkList(LinkList *list, DATATYPE *data)
{
    LinkNode *newnode = malloc(sizeof(LinkNode));
    if (NULL == newnode)
    {
        printf("InsertHeadLinkList malloc error\n");
        return 1;
    }
    memcpy(&newnode->data, data, sizeof(DATATYPE));
    newnode->next = NULL;

    newnode->next = list->head;
    list->head = newnode;
    list->clen++;
    return 0;
}











/**
 * @brief 在链表的最后新增元素
 *
 * @param list  待操作的链表
 * @param data 需要新增的数据
 * @return int 0 成功 1 失败
 */
int InsertTailLinkList(LinkList *list, DATATYPE *data)
{
    if (IsEmptyLinkList(list))
    {
        return InsertHeadLinkList(list, data);
    }
    LinkNode *newnode = malloc(sizeof(LinkNode));
    if (NULL == newnode)
    {
        printf("InsertTailLinkList malloc error\n");
        return 1;
    }
    memcpy(&newnode->data, data, sizeof(DATATYPE));
    newnode->next = NULL;

    LinkNode *tmp = list->head;
    while (tmp->next)
    {
        tmp = tmp->next;
    }

    tmp->next = newnode;
    list->clen++;

    return 0;
}











/**
 * @brief 显示单向链表中的数据
 *
 * @param list 待操作的单向链表 表头指针
 * @return int 0 表示成功
 */
int ShowLinkList(LinkList *list)
{
    LinkNode *tmp = list->head;
    while (NULL != tmp)
    {
        printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
               tmp->data.age, tmp->data.sex, tmp->data.score);
        tmp = tmp->next;  // i++
    }
    return 0;
}











/**
 * @brief 按照名字查找一个节点
 *
 * @param list  需要被查找的链表
 * @param name 需要被查找的用户的名字
 * @return LinkNode* !=NULL 成功  NULL 失败
 */
LinkNode *FindLinkList(LinkList *list, char *name)
{
    LinkNode *tmp = list->head;
    int len = GetSizeLinkList(list);
    int i = 0;
    for (i = 0; i < len; i++)
    {
        if (0 == strcmp(tmp->data.name, name))
        {
            return tmp;
        }
        tmp = tmp->next;
    }
    return NULL;  // (void*)0
}









面试常考!!!!!!
int DeleteLinkList(LinkList *list, char *name)
{
    if (IsEmptyLinkList(list))
    {
        printf("DeleteLinkList error\n");
        return 1;
    }

    LinkNode *tmp = NULL;
    LinkNode *prev = NULL;
    // 头删
    if (0 == strcmp(name, list->head->data.name))
    {
        tmp = list->head;
        list->head = list->head->next;
        free(tmp);
        list->clen--;
        return 0;
    }
    else
    {
        tmp = list->head;
        prev = list->head;

        while (1)
        {
            tmp = tmp->next;
            if (NULL == tmp)
            {
                break;
            }
            if (0 == strcmp(tmp->data.name, name))
            {
                prev->next = tmp->next;
                free(tmp);
                list->clen--;
                return 0;
            }
            prev = tmp;
        }
    }

    return 1;
}














/**
 * @brief
 *
 * @param list 根据名字修改节点的内容
 * @param name 需要被修改的用户名
 * @param newdata 要替换老用户的数据
 * @return int 0 成功  1失败
 */
int ModifyLinkList(LinkList *list, char *name, DATATYPE *newdata)
{
    LinkNode *ret = FindLinkList(list, name);
    if (NULL == ret)
    {
        printf("modify error\n");
        return 1;
    }

    memcpy(&ret->data, newdata, sizeof(DATATYPE));
    return 0;
}











/**
 * @brief 释放链表占用的内存 (表头+节点)
 *
 * @param list 需要释放的链表的表头指针
 * @return int 0 成功 !0 失败
 */
int DestroyLinkList(LinkList **list)
{
    LinkNode *tmp = NULL;
    while (1)
    {
        tmp = (*list)->head;
        if (NULL == tmp)
        {
            break;
        }
        (*list)->head = (*list)->head->next;
        free(tmp);
    }
    free(*list);
    *list = NULL;
    return 0;
}











int IsEmptyLinkList(LinkList *list)
{
    return 0 == list->clen;
}






int GetSizeLinkList(LinkList *list)
{
    return list->clen;
}













/**
 * @brief 单向链表的逆序
 *
 * @param list 待操作的链表
 */
void RevertLinkList(LinkList *list)
{
    LinkNode *prev = NULL;
    LinkNode *tmp = list->head;
    LinkNode *next = tmp->next;
    while (1)
    {
        tmp->next = prev;
        prev = tmp;
        tmp = next;
        if (NULL == tmp)
        {
            break;
        }
        next = next->next;
    }
    list->head = prev;
}











/**
 * @brief 查找链表中的 中间节点
 *
 * @param list  需要被操作的链表
 * @return LinkNode* NULL  失败  !NULL 找到的中间节点
 */
LinkNode *FindMidLinkList(LinkList *list)
{
    LinkNode *fast = list->head;
    LinkNode *slow = list->head;

    while (fast)
    {
        fast = fast->next;  //  fast = 1000
        if (NULL == fast)
        {
            break;
        }
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}









/**
 * @brief 查找链表倒数的第k个节点
 *
 * @param list 待操作的链表表头指针
 * @param k 倒数第k个
 * @return LinkNode* NULL 没有找到 , !NULL 成功
 */
LinkNode *FindLastKLinkList(LinkList *list, int k)
{
    LinkNode *slow = list->head;
    LinkNode *fast = list->head;
    int i = 0;
    for (i = 0; i < k; i++)
    {
        if (NULL == fast)
        {
            return NULL;
        }
        fast = fast->next;
    }

    while (fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

双向链表的函数:

bash 复制代码
#include "doulink.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>


/**
 * @brief 创建双向链表的表头结构
 *
 * @return 成功 返回指向表头结构的指针 失败返回NULL

 */
DouLinkList *CreateDouLinkList()
{
    DouLinkList *dl = malloc(sizeof(DouLinkList));  // 获取链表的内存空间
    if (NULL == dl)
    {
        printf("CreateDouLinkList malloc error\n");
        return NULL;
    }
    dl->head = NULL;  定义头节点
    dl->clen = 0;
    return dl;
}









/**
 * @brief 双向链表的头插
 *
 * @param dl 待操作的双向链表
 * @param data 需要插入的数据
 * @return int 0 成功 1失败
 */
int InsertHeadDouLinkList(DouLinkList *dl, DATATYPE *data)
{
    DouLinkNode *newnode = malloc(sizeof(DouLinkNode));
    if (NULL == newnode)
    {
        printf("InsertHeadDouLinkList malloc error\n");
        return 1;
    }
    memcpy(&newnode->data, data, sizeof(DATATYPE));
    newnode->next = NULL;
    newnode->prev = NULL;
    if (!IsEmptyDouLinkList(dl))
    {
        newnode->next = dl->head;
        dl->head->prev = newnode;
    }

    dl->head = newnode;
    dl->clen++;
    return 0;
}












int ShowDouLinkList(DouLinkList *dl, DIRECT dir(判断刷新的正反方向))
{
    DouLinkNode *tmp = dl->head;

    if (DIR_FORWARD == dir)  //因为插入顺序的特殊,正向输出反而是输出倒叙
    {
        while (tmp)
        {
            printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
                   tmp->data.age, tmp->data.sex, tmp->data.score);
            tmp = tmp->next;
        }
    }
    else  另一种输出方式
    {
        while (tmp->next)
        {
            tmp = tmp->next;
        }

        while (tmp)
        {
            printf("name:%s age:%d sex:%c score:%d\n", tmp->data.name,
                   tmp->data.age, tmp->data.sex, tmp->data.score);
            tmp = tmp->prev;
        }
    }
}
















int InserTailDouLinkList(DouLinkList *dl, DATATYPE *data)   插入最后一个节点
{
    if (NULL == dl)   // 判断结构体指针是否为空
    {
        return 1;
    }

    if (IsEmptyDouLinkList(dl))    //判断结构体本身是否为空
    {
        return InsertHeadDouLinkList(dl, data);  //把数据放在头节点的位置便是尾节点
    }
    else
    {
        DouLinkNode *tmp = dl->head;   //定义结构体数组指针
        while (tmp->next)
        {
            tmp = tmp->next;
        }   循环到最后一个节点

        DouLinkNode *newnode = malloc(sizeof(DouLinkNode));  //开辟新数据内存空间
        if (NULL == newnode)  开始进行判断
        {
            printf("InserTailDouLinkList malloc error\n");
            return 1;
        }
        memcpy(&newnode->data, data, sizeof(DATATYPE));   先把数据复制在新的节点之上
        newnode->next = NULL;   前后置空
        newnode->prev = NULL;

        tmp->next = newnode;  //最后节点的下一个指向 新节点
        newnode->prev = tmp;  //新节点的前一个指向新节点
    }
    dl->clen++;
    return 0;
}












/**
 * @brief 根据名字查找节点
 *
 * @param dl 需要被操作的链表
 * @param name 需要查找的用户名
 * @return DouLinkNode* NULL 失败 !=NULL 成功
 */
DouLinkNode *FindDouLinkList(DouLinkList *dl, char *name)
{
    DouLinkNode *tmp = dl->head;   
    while (NULL != tmp)
    {
        if (0 == strcmp(tmp->data.name, name))  
        {
            return tmp;
        }
        tmp = tmp->next;   //指向下一个开始寻找,直到找到为止
    }
    return NULL;
}











/**
 * @brief 根据名字修改 信息
 *
 * @param dl 需要操作的链表的指针
 * @param name 需要被修改信息的用户名
 * @param newdata 需要写入的新数据
 * @return int 0 成功 1 失败
 */
int ModifyDouLinkList(DouLinkList *dl, char *name, DATATYPE *newdata)
{
    if (NULL == dl)    //判断链表是否存在
    {
        return 1;
    }
    DouLinkNode *tmp = FindDouLinkList(dl, name);
    if (NULL == tmp)    
    {
        printf("modify error\n");
        return 1;
    }
 
    memcpy(&tmp->data, newdata, sizeof(DATATYPE));   //直接进行复制 
    return 0;
}













/**
 * @brief 根据删除名字删除一个节点
 *
 * @param dl 需要被操作的链表
 * @param name 需要被删除的用户名
 * @return int 0 成功, 1 失败
 */
int DeleteDouLinkList(DouLinkList *dl, char *name)
{
    DouLinkNode *tmp = FindDouLinkList(dl, name);
    if (NULL == tmp)
    {
        return 1;
    }
    //删除的就是第一个人
    if (dl->head == tmp)
    {
        dl->head = dl->head->next;
        dl->head->prev = NULL;
    }
    else
    {
        if (tmp->next != NULL)  //不是最后一个节点
        {
            tmp->next->prev = tmp->prev;
        }
        tmp->prev->next = tmp->next;
    }
    free(tmp);
    dl->clen--;
    return 0;
}








int IsEmptyDouLinkList(DouLinkList *dl)
{
    return NULL == dl->head;
}









GetSizeDouLinkList(DouLinkList *dl)
{
    return dl->clen;
}










/**
 * @brief 销毁链表,释放链表占用的内存空间
 *
 * @param dl 需要被操作的链表
 * @return int 0 成功 1失败
 */
int DestroyDouLinkList(DouLinkList *dl)
{
    if (NULL == dl)    // 判断链表是否为空
    {
        return 1;
    }
    DouLinkNode *tmp = dl->head;   
    while (tmp)
    {
        dl->head = dl->head->next;    //先保存下一个节点的位置
        free(tmp);      //释放本次的节点
        tmp = dl->head;    //指向下一个节点    
    }  //如此循环达到释放所有节点的目的
    free(dl);
    return 0;
}







int RevertDouLinkList(DouLinkList *dl)   倒置
{

    DouLinkNode* prev = NULL;   //链表的头节点反转后没有前驱,没有尾节点
    DouLinkNode* tmp = dl->head;   //确定各个指针的初始位置
    DouLinkNode* next = tmp->next;    //确定指针的初始指向
    while (tmp)
    {
        tmp->next = prev;    //开始逆序,把后放前
        tmp->prev = next;     //把前方后

        prev = tmp;         //指针开始后移  
        tmp = next;            
        if (NULL == tmp)
        { 
            break;
        }
        next = next->next;    //后移结束
    }

    dl->head = prev;  //最后把头节点倒置放在最后一个
    return 0;
}
相关推荐
2013编程爱好者6 小时前
【C++】树的基础
数据结构·二叉树··二叉树的遍历
NEXT066 小时前
二叉搜索树(BST)
前端·数据结构·面试
化学在逃硬闯CS6 小时前
Leetcode1382. 将二叉搜索树变平衡
数据结构·算法
季明洵9 小时前
Java实现单链表
java·开发语言·数据结构·算法·单链表
x***r1519 小时前
SuperScan4单文件扫描安装步骤详解(附端口扫描与主机存活检测教程)
windows
elseif1239 小时前
【C++】ST表求RMQ问题--代码+分析
数据结构·c++·算法
不爱学习的老登10 小时前
Windows客户端与Linux服务器配置ssh无密码登录
linux·服务器·windows
tju新生代魔迷11 小时前
数据结构:栈和队列
数据结构
Bear on Toilet11 小时前
树_构建多叉树_41 . 实现Trie(前缀树)
开发语言·数据结构·c++·算法·leetcode
陌陌龙11 小时前
全免去水印大师 v1.7.6 | 安卓端高效水印处理神器
windows