一组用来保存一种或者多种特定关系的数据的集合(组织和存储数据)
程序 = 数据结构 + 算法
一、线性结构
1.顺序表:数组
2.链式表:链表
数组和链表的区别:
1. 存储方式
- 数组:在内存中占用连续的空间。每个元素的地址可以通过基地址和索引计算得出。
- 链表:由一系列节点组成,每个节点包含数据和指向下一个节点的指针。节点在内存中不需要连续存储,可以分散在不同的内存位置。
2. 大小
-
数组:大小在创建时固定,无法动态调整。需要预先定义数组的大小。
-
链表:大小动态可变,可以根据需要添加或删除节点。不需要预先定义大小。
3. 访问效率
- 数组:支持随机访问,可以通过索引直接访问任意元素,时间复杂度为 O(1)。
- 链表:只能顺序访问,必须从头节点开始遍历,时间复杂度为 O(n)。
4. 插入和删除操作
- 数组:插入和删除操作较慢,尤其是在数组中间进行操作时,需要移动大量元素,时间复杂度为 O(n)。
- 链表:插入和删除操作较快,只需调整指针即可,时间复杂度为 O(1)(在已知位置的情况下)。
5. 内存管理
- 数组:在创建时分配固定大小的内存,可能会导致内存浪费或不足。
- 链表:节点在需要时动态分配内存,内存使用更灵活,但需要额外的指针存储开销。
6. 适用场景
- 数组:适用于需要频繁随机访问的场景,如查找、排序等。
- 链表:适用于需要频繁插入和删除的场景,如实现队列、栈等数据结构。
(1)单向链表:有头链表、无头链表
a.结点: 数据域、指针域
(2)有头链表
a.头插
b.尾插
c.头删
d.尾删
#include "link.h"
#include <stdlib.h>
#include <stdio.h>
#ifndef __LINK_H__
#define __LINK_H__
/*链表存储的数据的数据类型*/
typedef int DataType;
/*链表的结点类型*/
typedef struct node
{
DataType data; //数据域
struct node *pnext; //指针域:指向下一个结点
}Link_Node_t;
/*链表的对象类型*/
typedef struct link
{
Link_Node_t *phead; //链表头结点地址
int clen; //链表当前结点个数
}Link_t;
Link_t *create_link()//创建链表对象
{
Link_t *plink = (Link_t *)malloc(sizeof(Link_t));
if (NULL == plink)
{
perror("fail malloc");
return NULL;
}
plink->phead = NULL;
plink->clen = 0;
return plink;
}
int push_link_head(Link_t *plink, DataType data)//头插
{
Link_Node_t *pnode = (Link_Node_t *)malloc(sizeof(Link_Node_t));
if (NULL == pnode)
{
perror("fail malloc\n");
return -1;
}
pnode->data = data;
pnode->pnext = NULL;
pnode->pnext = plink->phead;
plink->phead = pnode;
plink->clen++;
return 0;
}
void traverse_link(Link_t *plink)//遍历
{
Link_Node_t *p = plink->phead;
while(p != NULL)
{
printf("%d ",p->data);
p = p->pnext;
}
printf("\n");
}
int push_link_tail(Link_t *plink,DataType data)//尾插
{
Link_Node_t *pnode = (Link_Node_t *)malloc(sizeof(Link_Node_t));
if(NULL == pnode)
{
perror("fail malloc\n");
return -1;
}
pnode->data = data;
pnode->pnext = NULL;
if(plink->phead == NULL)
{
plink->phead = pnode;
}
else
{
Link_Node_t *p = plink->phead;
while(p->pnext != NULL)
{
p = p->pnext;
}
p->pnext = pnode;
}
plink->clen++;
return 0;
}
int pop_link_head(Link_t *plink)//头删
{
if(NULL == plink->phead)
{
return 0;
}
else
{
Link_Node_t *p = plink->phead;
plink->phead = plink->phead->pnext;
free(p);
plink->clen--;
}
return 1;
}
int pop_link_tail(Link_t *plink)//尾删
{
if(NULL == plink->phead)
{
return 0;
}
else if(NULL == plink->phead->pnext)
{
pop_link_head(plink);
}
else
{
Link_Node_t *p = plink->phead;
while(p->pnext->pnext != NULL)
{
p = p->pnext;
}
free(p->pnext);
p->pnext = NULL;
plink->clen--;
return 1;
}
}
Link_Node_t *seek_link(Link_t *plink,DataType data)//查找任意节点
{
Link_Node_t *p = plink->phead;
while(p != NULL)
{
if(p->data == data)
{
return p->pnext;
}
p = p->pnext;
}
return NULL;
}
int change_link(Link_t *plink,DataType data1,DataType data2)//改变节点中的data
{
Link_Node_t *p = plink->phead;
while(p != NULL)
{
if(p->data == data1)
{
p->data = data2;
return 1;
}
p = p->pnext;
}
return 0;
}
int destory_link(Link_t *plink)//销毁链表
{
Link_Node_t *p = plink->phead;
while(p != NULL)
{
pop_link_head(plink);
p = p->pnext;
}
free(plink);
return 0;
}
Link_Node_t *seek_mid_node(Link_t *plink)//寻找中间节点
{
if(plink->phead == NULL)
{
return NULL;
}
else
{
Link_Node_t *p = plink->phead;
int i = (plink->clen) / 2;
for(int j = 0;j < i;++j)
{
p = p->pnext;
}
return p;
}
}
Link_Node_t *seek_counterback_node(Link_t *plink,int k)//寻找倒数节点
{
if(plink->phead == NULL || k > plink->clen)
{
printf("K > node\n");
return NULL;
}
else
{
Link_Node_t *p = plink->phead;
int i = plink->clen - k;
for(int j = 0;j < i;++j)
{
p = p->pnext;
}
return p;
}
}
int pop_node(Link_t *plink,int t)//删除节点
{
if (t <= 0 || plink->clen < t || plink->phead == NULL)
{
printf("t error\n");
return -1;
}
Link_Node_t *p = plink->phead;
if(t == 1)
{
pop_link_head(plink);
}
else
{
for (int i = 1; i < t - 1; ++i)
{
if (p->pnext == NULL)
{
printf("t > nodes\n");
return -1;
}
p = p->pnext;
}
Link_Node_t *del_node = p->pnext;
if (del_node == NULL)
{
printf("No node to delete\n");
return -1;
}
p->pnext = del_node->pnext;
free(del_node);
plink->clen--;
}
return 0;
}