一.数据结构
1.概念
数据结构研究的是存储位置的使用技巧
2.数据结构的两种角度
一个角度是数据在人的认识中的关系,这种关系叫做数据间的逻辑关系(逻辑结构)
另一个角度是数据在计算机内部存储时他们之间关系,这种关系叫丛数据间的物理关系(物理结构)
(1)逻辑结构的分类
集合: 所有数据看成一个整体,数据之间没有特殊的联系
线性结构: 所有的数据可以看成一条直线,数据之间存在一对一的关系
树状结构(层次结构): 在线性结构的基础上允许数据有多个跟随数据,数据之间存在一对多的关系
网状结构(图): 任何两个数据之间都可以有直接联系,数据之间存在多对多的关系
(2)物理结构的分类
顺序结构: 所有的数据在内存中连续排列,通常通过数组/动态内存来实现。
顺序结构可以随时找到任意一个数据,具有随机访问能力,便于查找和修改
不便于进行增加和删除,使用时不能调整大小,容易造成空间浪费
链式结构: 多个数据之间相互独立,有联系的数据之间用指针连接
链式结构通常使用结构体来实现,每个结构体数据叫做一个节点
链式结构便于增加和删除,为了实现增加时分配内存,删除时释放内存,节点的空间使用动态内存分配
链式结构没有随机访问能力,不便于查找和修改
逻辑结构和物理结构互不影响,任何一种逻辑结构可以用任何一种物理结构来实现
数据结构实现的是多个相关数据的管理功能,分为2个部分:
①多个相关的存储位置,通常就是提供一个结构体
②提供一组相关函数,这些函数可以让使用者以某种方式使用以上的存储位置(增删改查 创建 销毁 遍历)
二.顺序表
顺序表就是使用顺序结构实现的线性结构
定义sqlist.h
#ifndef _SQLIST_H_
#define _SQLIST_H_
#define N 100
typedef int T;
typedef struct sqlist{
T data[N];//存放需要存储的数据
int last;//记录数据个数
}sqlist_t,*sqlink_t;
sqlink_t init_sqlist();//初始化顺序表
void insert_by_index(sqlink_t sq,T index,T dt);//按位置添加
void delete_by_index(sqlink_t sq,T index);//按位置删除
void insert_tail(sqlink_t sq,T dt);//在尾部添加
void delete_tail(sqlink_t sq);//在尾部删除
void look(sqlink_t sq);//遍历顺序表
int search_by_value(sqlink_t sq,T dt);//按值查找(只查找第一个)
int search_by_index(sqlink_t sq,T index);//按位置查找
void change_by_index(sqlink_t sq,T index,T dt);//按位置修改
void change_by_value(sqlink_t sq,T value,T dt);//按值修改(修改所有)
void destroy_sqlist(sqlink_t *psq);//销毁顺序表
#endif
初始化顺序表
sqlink_t init_sqlist()
{
sqlink_t sq = (sqlink_t)malloc(sizeof(sqlist_t));
if(sq!=NULL){
//初始化数据个数为0
sq->last = 0;
}
return sq;
}
销毁顺序表
void destroy_sqlist(sqlink_t *psq)
{
free(*psq);
*psq = NULL;
}
按位置添加
void insert_by_index(sqlink_t sq,T index,T dt)
{
T i;
if(sq)
{
if(index<0||index>sq->last)
printf("out of range!\n");
else if(sq->last>=N)
printf("sqlist is full!");
else
{
for(i=sq->last;i>index;i--)
sq->date[i]=sq->date[i-1];
sq->date[index]=dt;
sq->last++;
}
}
else
printf("sqlist is NULL!\n");
}
按位置删除
void delete_by_index(sqlink_t sq,T index)
{
T i;
if(sq)
{
if(index<0||index>=sq->last)
printf("out of range!\n");
else
{
for(i=index;i<sq->last;i++)
sq->date[i]=sq->date[i+1];
sq->last--;
}
}
else
printf("sqlist is NULL!");
}
在尾部添加
void insert_tail(sqlink_t sq,T dt)
{
if(sq)
sq->date[sq->last++]=dt;
else
printf("sqlist is full!\n");
}
在尾部删除
void delete_tail(sqlink_t sq)
{
if(sq)
sq->last--;
else
printf("sqlist is null!\n");
}
按位置查找
int search_by_index(sqlink_t sq,T index)
{
if(sq)
{
if(index<0||index>sq->last)
return -ENOINDEX;
else
return sq->date[index];
}
else
{
printf("sqlist is NULL!");
return -ENULL;
}
}
按值查找(只查找第一个)
int search_by_value(sqlink_t sq,T dt)
{
T i;
if(sq)
{
for(i=0;i<sq->last;i++)
{
if(sq->date[i]==dt)
return i;
}
return -ENOMEM;
}
else
{
printf("sqlist is NULL!");
return -ENULL;
}
}
按位置修改
void change_by_index(sqlink_t sq,T index,T dt)
{
if(sq)
{
if(index<0||index>sq->last)
printf("out of range!\n");
else
sq->date[index]=dt;
}
else
{
printf("sqlist is NULL!");
}
}
按值修改(修改所有)
void change_by_value(sqlink_t sq,T value,T dt)
{
T i,falg;
if(sq)
{
for(i=0;i<sq->last;i++)
{
if(sq->date[i]==value)
{
sq->date[i]=dt;
flag=0;
}
}
}
else
printf("sqlist is NULL!");
if(flag==0)
return 0;
else
return -ENOMEM;
}
遍历顺序表
void look(sqlink_t sq)
{
T i;
for(i=0;i<sq->last;i++)
{
printf("%d ",sq->date[i]);
}
printf("\n");
}
三.单链表
1.概念
链表是链式的线性结构
单向链表中任何一个节点只能沿着一个方向访问下一个节点
单链表的节点 (结构体) 包括数据域和指针域,数据域存放节点存储的数据,指针域存放下一个节点的地址
单链表最后一个节点的指针域必须设置为NULL
通过单链表的第一个节点可以访问到链表的每一个节点,可以记录第一个节点的地址来代表整个链表
使用一个指针记录第一个节点的地址,这个指针叫头指针,可以用来代表整个链表
由于头指针表示法无法区分空链表和链表不存在,所以更倾向于使用头结点表示整个链表
头结点的指针域指向链表第一个节点,数据域不使用
如果需要频繁访问单链表的尾部,可以记录链表尾结点的地址
节点使用动态内存分配来分配空间,需要时申请,不需要时释放,不会造成空间浪费
方便进行插入和删除
单链表在头部操作效率较高,在尾部操作效率较低,如果我们频繁地在单链表的尾部进行操作,可以将单链表进行改进,将单链表改成单向循环链表
单向循环链表的最后一个节点的指针域指向头结点,记录最后一个节点的地址来代表单向循环链表
定义linklist.h
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
typedef int T;
typedef struct node{
T date;//数据域,存放节点的数据
struct node *next;//指针域,指向下一个节点
}linknode_t,*linklist_t;
linklist_t creat_emptylist();//创建单链表
linklist_t insert(linklist_t p,T dt);//从指定位置之后插入
linklist_t insert_head(linklist_t head,T dt);//从头部插入
linklist_t insert_tail(linklist_t head,T dt);//从尾部插入
linklist_t serach_by_index(linklist_t head,T index);//按位置查找
linklist_t serach_by_date(linklist_t head,T dt);//按值查找
linklist_t delete_by_index(linklist_t head,int index);//按位置删除
linklist_t delete_by_date(linklist_t head,T dt);//按值删除
void clear(linklist_t head);//清空单链表
void look(linklist_t head);//遍历单链表
void destory(linklist_t *phead);//销毁单链表
#endif
创建单链表
linklist_t creat_emptylist()
{
linklist_t head=(linklist_t)malloc(sizeof(linknode_t));
if(head)
{
head->next=NULL;//头节点的指针域指向NULL
//head->date=-1;
}
return head;
}
从指定位置之后插入
linklist_t insert(linklist_t p,T dt)
{
linklist_t newnode=(linklist_t)malloc(sizeof(linknode_t));//构造一个新节点
if (newnode)
{
newnode->date = dt;
newnode->next = p->next;
p->next = newnode;
}
return newnode;
}
从头部插入
linklist_t insert_head(linklist_t head,T dt)
{
return insert(head,dt);
}
从尾部插入
linklist_t insert_tail(linklist_t head,T dt)
{
while(head->next)
{
head = head->next;
}
return insert(head,dt);
}
按位置查找
linklist_t serach_by_index(linklist_t head,T index)
{
T i=0;
head = head->next;
while(head->next)
{
if(i==index)
return head;
head = head->next;
i++;
}
return NULL;
}
按值查找
linklist_t serach_by_date(linklist_t head,T dt)
{
head = head->next;
while(head)
{
if(head->date==dt)
return head;
head = head->next;
}
return NULL;
}
按位置删除
linklist_t delete_by_index(linklist_t head,int index)
{
linklist_t p = NULL,delete_node = NULL;
if(index<1)
{
printf("error index!\n");
return NULL;
}
delete_node = serach_by_index(head,index);
if(!delete_node)
return NULL;
if(index==1)
{
p = head;
}
else
p = serach_by_index(head,index-1);
//delete_node = p->next;
p->next = delete_node->next;
free(delete_node);
delete_node = NULL;
return p;
}
按值删除
linklist_t delete_by_date(linklist_t head,T dt)
{
linklist_t del_node = head;
head = head->next;
while(head)
{
if(head->date==dt)
break;
del_node = head;
head = head->next;
}
if(!head)
return NULL;
del_node->next = head->next;
free(head);
head = NULL;
return NULL;
}
遍历单链表
void look(linklist_t head)
{
head = head->next;
while(head)
{
printf("%d ",head->date);
head = head->next;
}
printf("\n");
}
清空单链表
void clear(linklist_t head)
{
linklist_t p = head->next,q = p;
head->next = NULL;
while(p)
{
q = p;
p = p->next;
free(q);
}
q = NULL;
}
销毁单链表
void destory(linklist_t *phead)
{
clear(*phead);
free(*phead);
*phead = NULL;
}