-
顺序存储
零个或多个数据元素的有限序列
元素之间是有顺序了。如果存在多个元素,第一个元素无前驱,最有一个没有后继,其他的元素只有一个前驱和一个后继。
当线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,为空表。在非空的表中每个元素都有一个确定的位置,如果a1是第一个元素,那么an就是第n个元素。
线性表顺序存储的优点、缺点
优点
1、无需为表中的逻辑关系增加额外的存储空间
2、可以快速随机访问元素O(1)
缺点
1、插入,删除元素需要移动元素o(n)
2、无法动态存储。
内存泄露检测工具
sudo apt-get install valgrind
valgrind ./all
seqlist.h
#ifndef _SEQLIST_H_
#define _SEQLIST_H_
typedef struct person {
char name[32];
char sex;
int age;
int score;
char word[100];
char mean[100];
}DATATYPE;
typedef struct list {
DATATYPE *head;
int tlen;
int clen;
}SeqList;
SeqList *CreateSeqList(int len); //创建顺序表
int DestroySeqList(SeqList *list); //销毁顺序表
int ShowSeqList(SeqList *list); //遍历将内容输出到屏幕
int InsertTailSeqList(SeqList *list, DATATYPE *data); //尾插
int IsFullSeqList(SeqList *list); //判断顺序表是否满了
int IsEmptySeqList(SeqList *list); //判断顺序表是否是空的
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos); //按位置插
int FindSeqList(SeqList *list, char *name); //查找
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata); //修改
int DeleteSeqList(SeqList *list, char *name); //删除
int ClearSeqList(SeqList *list); //清空
int GerSizeSeqList(SeqList*list); //
DATATYPE*GetItemSeqList(SeqList *list,int pos);
#endif
seqlist.c
SeqList *CreateSeqList(int len) //创建顺序表
{
SeqList *s1 = (SeqList*)malloc(sizeof(SeqList));
if(NULL== s1)
{
perror("CreateSeqList malloc");
return NULL;
}
s1->head = (DATATYPE*)malloc(sizeof(DATATYPE)*len);
if(NULL ==s1->head)
{
perror("CreateSeqList malloc 2");
return NULL;
}
s1->tlen = len;
s1->clen = 0;
return s1;
}
int InsertTailSeqList(SeqList *list,DATATYPE *data) //尾插
{
if(IsFullSeqList(list))
{
return 1;
}
memcpy(&list->head[list->clen],data,sizeof(DATATYPE));
list->clen++;
return 0;
}
int IsFullSeqList(SeqList *list) //判断顺序表是否满了
{
return list->clen == list->tlen;
}
int GerSizeList(SeqList*list) //得到clen的值
{
return list->clen;
}
int ShowSeqList(SeqList *list) //遍历将内容输出到屏幕
{
int len = GerSizeList(list);
int i = 0;
for(i = 0;i < len;i++)
{
printf("%s %c %d %d\n",list->head[i].name,list->head[i].sex,list->head[i].age,list->head[i].score);
}
return 0;
}
int IsEmptySeqList(SeqList *list) //判断顺序表是否为空
{
return 0 == list->clen;
}
int InsertPosSeqList(SeqList *list,DATATYPE *data,int pos) //按位置插
{
if(IsFullSeqList(list))
{
return -1;
}
if(pos > list->clen)
{
return -1;
}
int i = 0;
for(i = list->clen;pos < i;i--)
{
list->head[i] = list->head[i - 1];
}
memcpy(&list->head[pos],data,sizeof(DATATYPE));
list->clen++;
return 0;
}
int FindSeqList(SeqList *list,char *name) //查找
{
int len = GerSizeList(list);
int i = 0;
for(i = 0;i < len;++i)
{
if(0 == strcmp(list->head[i].name,name))
{
return i;
}
}
return -1;
}
DATATYPE* GetItemSeqList(SeqList* list,int pos) //查找到tom以后,得到tom一行的信息
{
if(pos < 0 || pos >= list->clen)
{
return NULL;
}
return &list->head[pos];
}
int ModifySeqList(SeqList *list, char *old, DATATYPE* newdata) //修改
{
int ret = FindSeqList(list,old);
if(-1 == ret)
{
return -1;
}
memcpy(&list->head[ret],newdata,sizeof(DATATYPE));
return 0;
}
int ClearSeqList(SeqList *list) //清空
{
list->clen = 0;
return 0;
}
int DestorySeqList(SeqList * list) 销毁顺序表
{
free(list->head);
free(list);
return 0;
}
int DeleteSeqList(SeqList* list,char *name) //删除
{
int i = 0;
int ret = FindSeqList(list,name);
if(-1 == ret)
{
return 1;
}
for(i = ret;i < list->clen;i++)
{
list->head[i] = list->head[i+1];
}
list->clen--;
return 0;
}
main.c
#include<stdio.h>
#include"seqlist.h"
int main(int argc,const char *argv[])
{
DATATYPE data[]={
{"tom",'m',20,90},
{"terry",'m',21,90},
{"liming",'m',22,91},
{"zhnagsan",'m',20,80},
{"lisi",'m',23,88},
{"tony",'m',19,90},
};
SeqList * s1 = CreateSeqList(10);
InsertTailSeqList(s1,&data[0]);
InsertTailSeqList(s1,&data[1]);
InsertTailSeqList(s1,&data[2]);
ShowSeqList(s1);
printf("---------pos-------\n");
InsertPosSeqList(s1,&data[3],100);
ShowSeqList(s1);
printf("----------find------\n");
int ret = FindSeqList(s1,"tom");
if(-1 == ret)
{
printf("can not find\n");
}
else
{
DATATYPE *tmp = GetItemSeqList(s1,ret);
printf("%s %d\n",tmp->name,tmp->age);
}
printf("--------modify-------\n");
ModifySeqList(s1,"liming",&data[1]);
ShowSeqList(s1);
printf("----------delete-----\n");
DeleteSeqList(s1,"tom");
ShowSeqList(s1);
DestroySeqList(s1);
return 0;
}
-
链式存储
解决顺序存储的缺点,插入和删除,动态存储问题。
特点:
线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素,存储单元可以是连续的,也可以不连续。可以被存储在任意内存未被占用的位置上。
所以前面的顺序表只需要存储数据元素信息就可以了。在链式结构中还需要一个元素存储下一个元素的地址。
为了表示每个数据元素,ai与其直接后继数据元素ai+1之间的逻辑关系,对ai来说,除了存储其本身的信息外,还需要存一个指示器直接后续的信息。把存储元素信息的域叫数据域,把存储直接后继位置的域叫指针域。这两部分信息组成数据元素ai的存储映像,叫结点(Node);
无头链表
有头链表:多一个空白表头
DouLinkList.h
#ifndef _DOULINKLIST_H_
#define _DOULINKLIST_H_
typedef struct person {
char name[32];
char sex;
int age;
int score;
}DATATYPE;
typedef enum {FORWARD,BACKWARD}DIRECT;
typedef struct dou_node {
DATATYPE data;
struct dou_node *next,*prev;
}DouLinkNode;
typedef struct list {
DouLinkNode *head;
int clen;
}DouLinkList;
typedef int (*pFun)(DATATYPE*data,void* arg);
DouLinkList *CreateLinkList(); //创建链表
int InsertHeadLinkList(DouLinkList *list, DATATYPE *data); //头插
int ShowLinkList(DouLinkList *list,DIRECT dire); //遍历将内容显示在屏幕上
//DouLinkNode *FindLinkList(DouLinkList *list, char *name);
DouLinkNode *FindLinkList(DouLinkList *list, pFun fun,void *arg); //查找
int InsertTailLinkList(DouLinkList *list, DATATYPE*data); //尾插
int InsertPosLinkList(DouLinkList *list, DATATYPE*data,int pos); //按位置插
int DeleteLinkList(DouLinkList *list, pFun fun,void *arg); //删除
int ModifyLinkList(DouLinkList *list,pFun fun,void * arg,DATATYPE *data); //修改
int DestroyLinkList(DouLinkList *list); //销毁链表
int IsEmptyLinkList(DouLinkList*list); //判断链表是否为空
int GetSizeDouLinkList(DouLinkList *list); //得到clen的值
#endif
DouLinkList.c
#include"./seqlist.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
SeqList *CreateSeqList(int len)
{
SeqList *s1 = (SeqList*)malloc(sizeof(SeqList));
if(NULL== s1)
{
perror("CreateSeqList malloc");
return NULL;
}
s1->head = (DATATYPE*)malloc(sizeof(DATATYPE)*len);
if(NULL ==s1->head)
{
perror("CreateSeqList malloc 2");
return NULL;
}
s1->tlen = len;
s1->clen = 0;
return s1;
}
int InsertTailSeqList(SeqList *list,DATATYPE *data)
{
if(IsFullSeqList(list))
{
return 1;
}
memcpy(&list->head[list->clen],data,sizeof(DATATYPE));
list->clen++;
return 0;
}
int IsFullSeqList(SeqList *list)
{
return list->clen == list->tlen;
}
int GerSizeList(SeqList*list)
{
return list->clen;
}
int ShowSeqList(SeqList *list)
{
int len = GerSizeList(list);
int i = 0;
for(i = 0;i < len;i++)
{
printf("%s %c %d %d\n",list->head[i].name,list->head[i].sex,list->head[i].age,list->head[i].score);
}
return 0;
}
int IsEmptySeqList(SeqList *list)
{
return 0 == list->clen;
}
int InsertPosSeqList(SeqList *list,DATATYPE *data,int pos)
{
if(IsFullSeqList(list))
{
return -1;
}
if(pos > list->clen)
{
return -1;
}
int i = 0;
for(i = list->clen;pos < i;i--)
{
list->head[i] = list->head[i - 1];
}
memcpy(&list->head[pos],data,sizeof(DATATYPE));
list->clen++;
return 0;
}
int FindSeqList(SeqList *list,char *name)
{
int len = GerSizeList(list);
int i = 0;
for(i = 0;i < len;++i)
{
if(0 == strcmp(list->head[i].name,name))
{
return i;
}
}
return -1;
}
DATATYPE* GetItemSeqList(SeqList* list,int pos)
{
if(pos < 0 || pos >= list->clen)
{
return NULL;
}
return &list->head[pos];
}
int ModifySeqList(SeqList *list, char *old, DATATYPE* newdata)
{
int ret = FindSeqList(list,old);
if(-1 == ret)
{
return -1;
}
memcpy(&list->head[ret],newdata,sizeof(DATATYPE));
return 0;
}
int ClearSeqList(SeqList *list)
{
list->clen = 0;
return 0;
}
int DestorySeqList(SeqList * list)
{
free(list->head);
free(list);
return 0;
}
int DeleteSeqList(SeqList* list,char *name)
{
int i = 0;
int ret = FindSeqList(list,name);
if(-1 == ret)
{
return 1;
}
for(i = ret;i < list->clen;i++)
{
list->head[i] = list->head[i+1];
}
list->clen--;
return 0;
}
main.c
#include <stdio.h>
#include "DouLinkList.h"
#include <string.h>
int findbyname(DATATYPE* data,void* arg)
{
return 0 == strcmp(data->name,(char*)arg);
}
int findbyage(DATATYPE* data,void* arg)
{
return data->age == *(int*)arg;
}
int main(int argc, char *argv[])
{
DouLinkList* ll =CreateLinkList();
DATATYPE data[]={
{"zhansan",'m',20,90},
{"lisi",'f',22,87},
{"wangmazi",'m',21,93},
{"guanerge",'m',40,60},
{"liuei",'m',42,83},
};
InsertHeadLinkList(ll,&data[0]);
InsertHeadLinkList(ll,&data[1]);
InsertHeadLinkList(ll,&data[2]);
ShowLinkList(ll,FORWARD );
printf("-------back-------------\n");
ShowLinkList(ll,BACKWARD);
//DouLinkNode* ret = FindLinkList(ll, "zhansan");
// DouLinkNode* ret = FindLinkList(ll,findbyname,"zhansan");
int age = 20;
DouLinkNode* ret = FindLinkList(ll,findbyage,&age);
if(NULL == ret)
{
printf("can't find\n");
}
else
{
printf("find it,%s %d\n",ret->data.name,ret->data.score);
}
printf("-------------tail--------------\n");
InsertPosLinkList(ll,&data[3],2);
ShowLinkList(ll,FORWARD );
printf("-------back-------------\n");
ShowLinkList(ll,BACKWARD);
printf("-------------del--------------\n");
DeleteLinkList(ll,findbyname,"zhansan");
ShowLinkList(ll,FORWARD );
printf("-------back-------------\n");
ShowLinkList(ll,BACKWARD);
printf("------modify------\n");
ModifyLinkList(ll,findbyname,"zhansan",&data[4]);
ShowLinkList(ll,FORWARD);
printf("-------back------\n");
ShowLinkList(ll,FORWARD);
printf("--------destroy----\n");
DestroyLinkList(ll);
// ShowLinkList(ll,FORWARD);
printf("-------back------\n");
// ShowLinkList(ll,FORWARD);
return 0;
}
-
总结
顺序表和链表 优缺点
-
存储方式:
顺序表是一段连续的存储单元
链表是逻辑结构连续物理结构(在内存中的表现形式)不连续
-
时间性能
查找 顺序表O(1) 链表 O(n)
插入和删除 顺序表 O(n) 链表 O(1)
-
空间性能
顺序表: 需要预先分配空间,大小固定
链表 :不需要预先分配,大小可变,动态分配
-
循环链表
简单的来说,就是将原来单链表中最有一个元素的next指针指向第一个元素或头结点,链表就成了一个环,头尾相连,就成了循环链表。circultlar linker list.
注意非空表,和空表。多数会加入头结点。
原来结束的条件是 : p->next != NULL ------->>>>> p-next != Head