linux------数据结构
数据结构:
1.衡量一个程序是否优秀:
1.时间复杂度:
数据量增长与程序运行时间的比例关系以函数描述称为时间渐进复杂度函数,简称时间复杂度
O(c) > O(logn) > O(n) > O(nlogn) > O(n^2) > O(n^3) > O(2^n)
2.空间复杂度:
数据量增长与程序所占用空间的比例关系称为空间复杂度
2.数据结构:
数据之间的关系
逻辑结构:
1. 线性结构
一对一 表
2. 非线性结构
一对多 树
多对多 图
存储结构:
1. 顺序存储结构
2. 链式存储结构
3. 离散存储
4. 索引存储
3.程序:
程序 = 数据结构 + 算法
4.数据结构:
顺序表
链式表
顺序栈
链式栈
顺序队列
链式队列
树
二叉树
常见的排序查找算法
安装内存泄露检测工具:
sudo apt-get install valgrind
检测方法:
valgrind --tool=memcheck --leak-check=full ./a.out
5.顺序表:
1.整形
#include "seqlist.h"
#include <stdio.h>
int ShowFun(void *pElement, void *arg)
{
int *pData = pElement;
printf("%d ", *pData);
return 0;
}
int UpdateFun(void *pElement, void *arg)
{
int *pData = pElement;
if (*pData == 4)
{
*pData = 40;
}
return 0;
}
int FindFun(void *pElement, void *arg)
{
int *pData = pElement;
if (*pData == 30)
{
return 1;
}
else
{
(*(int *)arg)++;
}
return 0;
}
int main(void)
{
SeqList *pseqlist = NULL;
int val = 0;
int n = 0;
pseqlist = CreateSeqList(10);
AppendSeqList(pseqlist, 1);
AppendSeqList(pseqlist, 2);
AppendSeqList(pseqlist, 3);
AppendSeqList(pseqlist, 4);
AppendSeqList(pseqlist, 5);
PosInsertSeqList(pseqlist, 0, 10);
PosInsertSeqList(pseqlist, 3, 30);
printf("===============================\n");
printf("顺序表当前元素个数:%d/%d\n", GetCountSeqList(pseqlist), GetCapacitySeqList(pseqlist));
printf("===============================\n");
printf("元素内容:\n");
ForeachSeqList(pseqlist, ShowFun, NULL);
printf("\n");
printf("===============================\n");
printf("修改元素:\n");
ForeachSeqList(pseqlist, UpdateFun, NULL);
printf("===============================\n");
printf("元素内容:\n");
ForeachSeqList(pseqlist, ShowFun, NULL);
printf("\n");
printf("===============================\n");
printf("查找元素:\n");
n = 0;
ForeachSeqList(pseqlist, FindFun, &n);
printf("n = %d\n", n);
printf("===============================\n");
printf("删除元素:\n");
n = 0;
ForeachSeqList(pseqlist, FindFun, &n);
DeleteSeqList(pseqlist, n);
DeleteSeqList(pseqlist, 0);
DeleteSeqList(pseqlist, GetCountSeqList(pseqlist)-1);
printf("===============================\n");
printf("元素内容:\n");
ForeachSeqList(pseqlist, ShowFun, NULL);
printf("\n");
printf("===============================\n");
ClearSeqList(pseqlist);
printf("元素内容:\n");
ForeachSeqList(pseqlist, ShowFun, NULL);
printf("\n");
printf("===============================\n");
DestroySeqList(&pseqlist);
return 0;
}
#include "seqlist.h"
#include <stdlib.h>
#include <stdio.h>
//创建顺序表
SeqList *CreateSeqList(int MaxLen)
{
SeqList *pTmpList = NULL;
//1.申请标签空间
pTmpList = malloc(sizeof(*pTmpList));
if (NULL == pTmpList)
{
return NULL;
}
//2.对标签中的所有成员赋值
pTmpList->cLen = 0;
pTmpList->tLen = MaxLen;
//3.申请存放数据的空间
pTmpList->pData = malloc(MaxLen * sizeof(DataType));
if (NULL == pTmpList->pData)
{
return NULL;
}
//4.返回标签首地址
return pTmpList;
}
//顺序表是否已满
int IsFullSeqList(SeqList *pTmpList)
{
return pTmpList->cLen == pTmpList->tLen ? 1 : 0;
}
//顺序表是否为空
int IsEmptySeqList(SeqList *pTmpList)
{
return pTmpList->cLen == 0 ? 1 : 0;
}
//获得顺序表中元素个数
int GetCountSeqList(SeqList *pTmpList)
{
return pTmpList->cLen;
}
//获得顺序表中元素的容量
int GetCapacitySeqList(SeqList *pTmpList)
{
return pTmpList->tLen;
}
//末尾添加
int AppendSeqList(SeqList *pTmpList, DataType TmpData)
{
if (IsFullSeqList(pTmpList))
{
return -1;
}
pTmpList->pData[pTmpList->cLen] = TmpData;
pTmpList->cLen++;
return 0;
}
//指定位置插入
//注意:
// 返回-1 表示顺序表已满
// 返回-2 表示插入数据的位置错误
int PosInsertSeqList(SeqList *pTmpList, int Pos, DataType TmpData)
{
int n = 0;
if (IsFullSeqList(pTmpList))
{
return -1;
}
//错误的插入位置
if (!(Pos >= 0 && Pos <= pTmpList->cLen))
{
return -2;
}
for (n = pTmpList->cLen; n > Pos; n--)
{
pTmpList->pData[n] = pTmpList->pData[n-1];
}
pTmpList->pData[Pos] = TmpData;
pTmpList->cLen++;
return 0;
}
//元素遍历
//参数:
// pFun:对遍历到的每个数据的操作方法
// arg:对pFun函数的传参
//返回值:
// 成功返回0
// 失败返回-1
int ForeachSeqList(SeqList *pTmpList, int (*pFun)(void *Element, void *arg), void *arg)
{
int i = 0;
int ret = 0;
for (i = 0; i < pTmpList->cLen; i++)
{
ret = pFun(&pTmpList->pData[i], arg);
if (ret != 0)
{
return -1;
}
}
return 0;
}
//删除
int DeleteSeqList(SeqList *pTmpList, int Pos)
{
int i = 0;
int n = 0;
if (IsEmptySeqList(pTmpList))
{
return -1;
}
//删除元素的位置是否异常
if (!(Pos >= 0 && Pos < pTmpList->cLen))
{
return -2;
}
for (n = Pos; n < pTmpList->cLen-1; n++)
{
pTmpList->pData[n] = pTmpList->pData[n+1];
}
pTmpList->cLen--;
return 0;
}
//清0
int ClearSeqList(SeqList *pTmpList)
{
pTmpList->cLen = 0;
return 0;
}
//销毁
int DestroySeqList(SeqList **ppTmpList)
{
free((*ppTmpList)->pData);
free((*ppTmpList));
*ppTmpList = NULL;
return 0;
}
#ifndef __SEQLIST_H__
#define __SEQLIST_H__
typedef struct str
{
char data[128];
}str_t;
//存储数据类型
typedef str_t DataType;
//顺序表标签结构
typedef struct list
{
DataType *pData; //存放数据空间首地址
int tLen; //最大存放元素个数
int cLen; //当前元素个数
}SeqList;
extern SeqList *CreateSeqList(int MaxLen);
extern SeqList *CreateSeqList(int MaxLen);
extern int IsEmptySeqList(SeqList *pTmpList);
extern int IsFullSeqList(SeqList *pTmpList);
extern int GetCountSeqList(SeqList *pTmpList);
extern int GetCapacitySeqList(SeqList *pTmpList);
extern int AppendSeqList(SeqList *pTmpList, DataType TmpData);
extern int PosInsertSeqList(SeqList *pTmpList, int Pos, DataType TmpData);
extern int ForeachSeqList(SeqList *pTmpList, int (*pFun)(void *Element, void *arg), void *arg);
#endif
2.字符串型
#include "seqlist.h"
#include <stdio.h>
int IpShowFun(void *pElement, void *arg)
{
DataType *pData = pElement;
printf("IP:%s\n", pData->data);
printf("-------------------------\n");
return 0;
}
int main(void)
{
SeqList *pseqlist = NULL;
int val = 0;
pseqlist = CreateSeqList(10000);
DataType TmpData1 = {"192.168.0.100"};
AppendSeqList(pseqlist, TmpData1);
DataType TmpData2 = {"192.168.0.110"};
AppendSeqList(pseqlist, TmpData2);
DataType TmpData3 = {"192.168.0.120"};
AppendSeqList(pseqlist, TmpData3);
DataType TmpData4 = {"192.168.0.130"};
AppendSeqList(pseqlist, TmpData4);
DataType TmpData5 = {"192.168.0.140"};
AppendSeqList(pseqlist, TmpData5);
printf("===============================\n");
printf("当前IP个数:%d/%d\n", GetCountSeqList(pseqlist), GetCapacitySeqList(pseqlist));
printf("===============================\n");
printf("已经登录用户的IP列表\n");
ForeachSeqList(pseqlist, IpShowFun, NULL);
printf("===============================\n");
return 0;
}
#include "seqlist.h"
#include <stdlib.h>
#include <stdio.h>
//创建顺序表
SeqList *CreateSeqList(int MaxLen)
{
SeqList *pTmpList = NULL;
//1.申请标签空间
pTmpList = malloc(sizeof(*pTmpList));
if (NULL == pTmpList)
{
return NULL;
}
//2.对标签中的所有成员赋值
pTmpList->cLen = 0;
pTmpList->tLen = MaxLen;
//3.申请存放数据的空间
pTmpList->pData = malloc(MaxLen * sizeof(DataType));
if (NULL == pTmpList->pData)
{
return NULL;
}
//4.返回标签首地址
return pTmpList;
}
//顺序表是否已满
int IsFullSeqList(SeqList *pTmpList)
{
return pTmpList->cLen == pTmpList->tLen ? 1 : 0;
}
//顺序表是否为空
int IsEmptySeqList(SeqList *pTmpList)
{
return pTmpList->cLen == 0 ? 1 : 0;
}
//获得顺序表中元素个数
int GetCountSeqList(SeqList *pTmpList)
{
return pTmpList->cLen;
}
//获得顺序表中元素的容量
int GetCapacitySeqList(SeqList *pTmpList)
{
return pTmpList->tLen;
}
//末尾添加
int AppendSeqList(SeqList *pTmpList, DataType TmpData)
{
if (IsFullSeqList(pTmpList))
{
return -1;
}
pTmpList->pData[pTmpList->cLen] = TmpData;
pTmpList->cLen++;
return 0;
}
//指定位置插入
//注意:
// 返回-1 表示顺序表已满
// 返回-2 表示插入数据的位置错误
int PosInsertSeqList(SeqList *pTmpList, int Pos, DataType TmpData)
{
int n = 0;
if (IsFullSeqList(pTmpList))
{
return -1;
}
//错误的插入位置
if (!(Pos >= 0 && Pos <= pTmpList->cLen))
{
return -2;
}
for (n = pTmpList->cLen; n > Pos; n--)
{
pTmpList->pData[n] = pTmpList->pData[n-1];
}
pTmpList->pData[Pos] = TmpData;
pTmpList->cLen++;
return 0;
}
//元素遍历
//参数:
// pFun:对遍历到的每个数据的操作方法
// arg:对pFun函数的传参
//返回值:
// 成功返回0
// 失败返回-1
int ForeachSeqList(SeqList *pTmpList, int (*pFun)(void *Element, void *arg), void *arg)
{
int i = 0;
int ret = 0;
for (i = 0; i < pTmpList->cLen; i++)
{
ret = pFun(&pTmpList->pData[i], arg);
if (ret != 0)
{
return -1;
}
}
return 0;
}
//修改
//查询
//销毁
3.结构体
#include "seqlist.h"
#include <stdio.h>
int IpShowFun(void *pElement, void *arg)
{
DataType *pData = pElement;
printf("IP:%s\n", pData->address);
printf("Port:%d\n", pData->port);
printf("-------------------------\n");
return 0;
}
int main(void)
{
SeqList *pseqlist = NULL;
int val = 0;
pseqlist = CreateSeqList(10000);
DataType TmpData1 = {"192.168.0.100", 30000};
AppendSeqList(pseqlist, TmpData1);
DataType TmpData2 = {"192.168.0.110", 30000};
AppendSeqList(pseqlist, TmpData2);
DataType TmpData3 = {"192.168.0.120", 30000};
AppendSeqList(pseqlist, TmpData3);
DataType TmpData4 = {"192.168.0.130", 30000};
AppendSeqList(pseqlist, TmpData4);
DataType TmpData5 = {"192.168.0.140", 30000};
AppendSeqList(pseqlist, TmpData5);
printf("===============================\n");
printf("当前IP个数:%d/%d\n", GetCountSeqList(pseqlist), GetCapacitySeqList(pseqlist));
printf("===============================\n");
printf("已经登录用户的IP列表\n");
ForeachSeqList(pseqlist, IpShowFun, NULL);
printf("===============================\n");
return 0;
}
#include "seqlist.h"
#include <stdlib.h>
#include <stdio.h>
//创建顺序表
SeqList *CreateSeqList(int MaxLen)
{
SeqList *pTmpList = NULL;
//1.申请标签空间
pTmpList = malloc(sizeof(*pTmpList));
if (NULL == pTmpList)
{
return NULL;
}
//2.对标签中的所有成员赋值
pTmpList->cLen = 0;
pTmpList->tLen = MaxLen;
//3.申请存放数据的空间
pTmpList->pData = malloc(MaxLen * sizeof(DataType));
if (NULL == pTmpList->pData)
{
return NULL;
}
//4.返回标签首地址
return pTmpList;
}
//顺序表是否已满
int IsFullSeqList(SeqList *pTmpList)
{
return pTmpList->cLen == pTmpList->tLen ? 1 : 0;
}
//顺序表是否为空
int IsEmptySeqList(SeqList *pTmpList)
{
return pTmpList->cLen == 0 ? 1 : 0;
}
//获得顺序表中元素个数
int GetCountSeqList(SeqList *pTmpList)
{
return pTmpList->cLen;
}
//获得顺序表中元素的容量
int GetCapacitySeqList(SeqList *pTmpList)
{
return pTmpList->tLen;
}
//末尾添加
int AppendSeqList(SeqList *pTmpList, DataType TmpData)
{
if (IsFullSeqList(pTmpList))
{
return -1;
}
pTmpList->pData[pTmpList->cLen] = TmpData;
pTmpList->cLen++;
return 0;
}
//指定位置插入
//注意:
// 返回-1 表示顺序表已满
// 返回-2 表示插入数据的位置错误
int PosInsertSeqList(SeqList *pTmpList, int Pos, DataType TmpData)
{
int n = 0;
if (IsFullSeqList(pTmpList))
{
return -1;
}
//错误的插入位置
if (!(Pos >= 0 && Pos <= pTmpList->cLen))
{
return -2;
}
for (n = pTmpList->cLen; n > Pos; n--)
{
pTmpList->pData[n] = pTmpList->pData[n-1];
}
pTmpList->pData[Pos] = TmpData;
pTmpList->cLen++;
return 0;
}
//元素遍历
//参数:
// pFun:对遍历到的每个数据的操作方法
// arg:对pFun函数的传参
//返回值:
// 成功返回0
// 失败返回-1
int ForeachSeqList(SeqList *pTmpList, int (*pFun)(void *Element, void *arg), void *arg)
{
int i = 0;
int ret = 0;
for (i = 0; i < pTmpList->cLen; i++)
{
ret = pFun(&pTmpList->pData[i], arg);
if (ret != 0)
{
return -1;
}
}
return 0;
}
//修改
//查询
//销毁
#ifndef __SEQLIST_H__
#define __SEQLIST_H__
//数据对象类型
typedef struct clientinfo
{
char address[256];
int port;
}clientinto_t;
//存储数据类型
typedef clientinto_t DataType;
//顺序表标签结构
typedef struct list
{
DataType *pData; //存放数据空间首地址
int tLen; //最大存放元素个数
int cLen; //当前元素个数
}SeqList;
extern SeqList *CreateSeqList(int MaxLen);
extern SeqList *CreateSeqList(int MaxLen);
extern int IsEmptySeqList(SeqList *pTmpList);
extern int IsFullSeqList(SeqList *pTmpList);
extern int GetCountSeqList(SeqList *pTmpList);
extern int GetCapacitySeqList(SeqList *pTmpList);
extern int AppendSeqList(SeqList *pTmpList, DataType TmpData);
extern int PosInsertSeqList(SeqList *pTmpList, int Pos, DataType TmpData);
extern int ForeachSeqList(SeqList *pTmpList, int (*pFun)(void *Element, void *arg), void *arg);
#endif
6.链表:
1.空间可以不连续,访问元素不方便
2.链表需要更大的空间存放数据和节点地址
3.链表空间不连续,使得理论上长度是无限的
4.链表的插入和删除效率很高
链表的分类:
1.单向链表
2.双向链表
3.循环链表
4.内核链表
1.单向链表
1.段错误调试方法:
1.按照网上的方法配置Ubuntu,允许生成core文件
2.重新编译代码并加入-g选项(允许进行GDB调试)
3.ulimit -c unlimited
不限制core文件的生成的大小
4.执行代码,复现段错误,产生包含出错信息的core文件(检查core文件是否生成)
5.gdb a.out core
查看段错误产生的位置
bt
查看段错误时的堆栈信息
p 变量名
查看段错误时的变量信息
2.vscode的调试方法
3.单向链表操作:
基本操作:
1.创建
2.销毁
3.插入
4.删除
5.打印
6.修改
7.查询
复杂操作:
1.查找链表中间节点
2.查找链表倒数第k个节点
3.链表的倒置(反转)
4.链表的排序(冒泡排序、选择排序)
5.已知链表中间某个节点地址,不知道头结点地址,如何删除该节点
6.如何判断一个链表是否有环?环长?环的入口位置?
是否有环:快指针每次走2步,慢指针每次走1步,快慢指针相遇则说明有环
如何计算环长:标记相遇的位置,让指针继续向后走,没走一步计算器自加,走回到标记位置,则计算器值即为环长
如何计算环入口位置:将一个指针从第一个节点向后走,将一个指针从相遇点向后走,两个指针相遇的位置即为环入口的位置