数据结构:
1. 定义:
一组用来保存一种或者多种特定关系的数据的集合(组织和存储数据)
1. 程序设计:
将现实中大量而复杂的问题以特定的数据类型和特定的数据结构存储在内存中,并在此基础上实现某个特定的功能的操作(程序 = 数据结构 + 算法)
**高内聚:**一个功能模块只干一件事
**低耦合:**功能模块与功能模块之间的耦合度要低
**可读性:**程序需要添加注释
**健壮性:**程序在运行过程中不能产生异常
2. MVC软件设计架构:
M:mode,数据的管理(数据结构)
V:view,视图,数据的反映及人机交互
C:ctrl,逻辑控制
2. 数据与数据之间的关系
1. 数据的逻辑结构:数据元素与元素之间的关系
集合:关系平等
**线性结构:**元素之间一对一的关系(表(数组、链表)),队列,栈)
**树形结构:**元素之间一对多的关系(二叉树)
图形结构:元素之间多对多的关系(网状结构)
2. 数据的物理结构:数据的逻辑结构在计算机内存中的存储形式
1. 顺序存储:
采用一段连续的内存空间保存元素
**优点:**数据访问方便
**缺点:**1. 数据插入删除需要移动大量的元素
-
需要预分配内存空间
-
容易造成存储空间碎片
2. 链式存储:
采用一种非连续的内存空间保存元素
**优点:**1. 插入删除数据效率高
- 不需要预分频内存
**缺点:**访问元素必须遍历,效率低
3. 索引存储:
通过关键字构建索引表,通过索引表来找到数据的存储位置
4. 散列存储(哈希存储):
将数据元素的存储位置与关键码之间建立确定对应关系从而实现查找的存储方式
索引存储和散列存储都是为了提高数据的查找速度
单向链表:
1. 有头链表:
第一个链表节点中不存储有效数据
2. 无头链表:
第一个链表结点中存储有效数据
1. 定义无头链表的句柄和结点:
cpp
#ifndef _LINK_H_
#define _LINK_H_
typedef int DATA_TYPE;
typedef struct node
{
DATA_TYPE data;
struct node *pnext;
}LINK_NODE;
typedef struct list
{
LINK_NODE *phead;
int curlen;
}LINK_LIST;
#endif
说明其中struct node还未定义的时候就用struct node *定义pnext:因为不管是char *还是int *等还是struct node *都是指针类型,它都占8个字节,但是如果不加*,那么系统就不知道结构体构建的内存空间的大小,所以就会报错。
2. 创建无头链表:
cpp
LINK_LIST *Create_Link(void)
{
LINK_LIST *plist = malloc(sizeof(LINK_LIST));
if(plist == NULL)
{
return NULL;
}
plist->phead = NULL;
plist->curlen = 0;
return plist;
}
3. 头插法:
cpp
int Push_Head_Link(LINK_LIST *plist, DATA_TYPE data)
{
LINK_NODE *pnode = malloc(sizeof(LINK_NODE));
if(pnode == NULL)
{
return -1;
}
pnode->data = data;
pnode->pnext = NULL;
pnode->pnext = plist->phead;
plist->phead = pnode;
plist->curlen++;
return 0;
}
4. 尾插法:
cpp
int Push_Tail_Link(LINK_LIST *plist, DATA_TYPE data)
{
LINK_NODE *pnode = malloc((sizeof(LINK_NODE)));
if(pnode == NULL)
{
return -1;
}
pnode->data = data;
pnode->pnext = NULL;
LINK_NODE *ptmp = plist->phead;
if(ptmp == NULL)
{
ptmp = pnode;
}
else
{
while(ptmp->pnext != NULL)
{
ptmp = ptmp->pnext;
}
ptmp->pnext = pnode;
}
plist->curlen++;
return 0;
}
5. 遍历:
cpp
int list_for_each(LINK_LIST *plist)
{
LINK_NODE *ptmp = plist->phead;
while(ptmp != NULL)
{
printf("%d ", ptmp->data);
ptmp = ptmp->pnext;
}
printf("\n");
return 0;
}
6. 尾删法:
cpp
int Pop_Tail_Link(LINK_LIST *plist)
{
LINK_NODE *ptmp = plist->phead;
if(ptmp == NULL)
{
return 0;
}
else if(ptmp->pnext == NULL)
{
free(ptmp);
plist->phead = NULL;
}
else
{
while(ptmp->pnext->pnext == NULL)
{
ptmp = ptmp->pnext;
}
free(ptmp->pnext);
ptmp->pnext = NULL;
}
plist->curlen--;
return 0;
}
7. 头删法:
cpp
int Pop_Head_Link(LINK_LIST *plist)
{
LINK_NODE *ptmp = plist->phead;
if(ptmp == NULL)
{
return 0;
}
else if(ptmp->pnext == NULL)
{
free(ptmp);
plist->phead = NULL;
}
else
{
plist->phead = plist->phead->pnext;
free(ptmp);
}
plist->curlen--;
return 0;
}
8. 查找:
cpp
LINK_NODE *Find_Link_Node(LINK_LIST *plist, DATA_TYPE data)
{
LINK_NODE *ptmp = plist->phead;
while(ptmp != NULL)
{
if(ptmp->data == data)
{
return ptmp;
}
ptmp = ptmp->pnext;
}
return NULL;
}
9. 修改:
cpp
int Replace_link_data(LINK_LIST *plist, DATA_TYPE olddata, DATA_TYPE newdata)
{
LINK_NODE *ptmp = plist->phead;
while(ptmp != NULL)
{
if(ptmp->data = olddata)
{
ptmp->data = newdata;
}
ptmp = ptmp->pnext;
}
return 0;
}
10. 销毁:
cpp
int Destroy_Link(LINK_LIST *plist)
{
LINK_NODE *ptmp = plist->phead;
LINK_NODE *pfree = plist->phead;
while(ptmp != NULL)
{
ptmp = ptmp->pnext;
free(pfree);
pfree = ptmp;
}
free(plist);
return 0;
}
在链表用完以后需要销毁,是为了防止内存泄露(内存空间完全被占用,没有内存可以分配),可以利用valgrind判断是否发生内存泄露。
bash
sudo apt-get install valgrind
valgrind ./a.out
malloc7次,释放7次,所以并没有发生内存泄露