1.数据元素之间不是独立的,存在特定的关系,这些关系即结构。所以数据结构是指数据对象中数据元素之间的关系。
数据结构分为逻辑结构和物理结构。
逻辑结构分为:
集合结构:数据元素之间没有特别的关系,仅同属相同集合。
线性结构:数据元素之间是一对一的关系。
树形结构:数据元素之间存在一对多的层次关系。
图形结构:数据元素之间是多对多的关系。
物理结构分为:
顺序存储结构:将数据存储在地址连续的存储单元里。
链式存储结构:将数据存储在任意的存储单元里,通过保存地址的方式找到相关联的数据元素。
线性表的定义:
线性表(List)是零个或多个数据元素的集合。
线性表中的数据元素之间是有顺序的。
线性表中的数据元素个数是有限的。
线性表中的数据元素的类型必须相同。
性质:
a0为线性表的第一个元素只有一个后继。
an为线性表的最后一个元素,只有一个前驱。
除a0和an外的其他元素既有前驱又有后继。
线性表能够逐项访问和顺序存取。
2.顺序存储结构:线性表的顺序存储结构指的是用一段地址连续的存储单元依次存储线性表的数据元素。
(1)插入元素算法:
Status ListInsert(SqList *L,int i,ElemType e)
{
int k;
if (L->length==MAXSIZE) /* 顺序线性表已经满 */
return ERROR;
if (i<1 || i>L->length+1) /* 当i比第一位置小或者比最后一位置后一位置还要大时 */
return ERROR;
if (i<=L->length) /* 若插入数据位置不在表尾 */
{
for(k=L->length-1;k>=i-1;k--) /* 将要插入位置之后的数据元素向后移动一位 */
L->data[k+1]=L->data[k];
}
L->data[i-1]=e; /* 将新元素插入 */
L->length++;
return OK;
}
(2)删除元素算法:
Status ListDelete(SqList *L,int i,ElemType *e)
{
int k;
if (L->length==0) /* 线性表为空 */
return ERROR;
if (i<1 || i>L->length) /* 删除位置不正确 */
return ERROR;
*e=L->data[i-1];
if (i<L->length) /* 如果删除不是最后位置 */
{
for(k=i;k<L->length;k++) /* 将删除位置后继元素前移 */
L->data[k-1]=L->data[k];
}
L->length--;
return OK;
}
3.链式存储结构:
为了表示每个元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息。
链表的概念:
表头结点------链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息。
数据结点------链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息。
尾结点--------链表中的最后一个数据结点,其下一元素指针为空,表示无后继。
N个结点链接成一个链表,即为线性表(a1,a2,…an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫单链表。
链表中第一个结点的存储位置叫做头指针;最后一个结点指针为空(NULL)。
可在单链表的第一个结点前附设一个结点,称为头结点。可以不存储任何信息。
(1)单链表整表创建的算法思路:
void CreateListHead(LinkList *L, int n)
{
LinkList p;
int i;
srand(time(0)); /* 初始化随机数种子 */
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; /* 先建立一个带头结点的单链表 */
for (i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node)); /* 生成新结点 */
p->data = rand()%100+1; /* 随机生成100以内的数字 */
p->next = (*L)->next;
(*L)->next = p;
/* 插入到表头 */
}
}
上面那种叫做头插法,我们也可以通过尾插法来创建一个链表
void CreateListTail(LinkList *L, int n)
{
LinkList p,r;
int i;
srand(time(0)); /* 初始化随机数种子 */
*L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
r=*L; /* r为指向尾部的结点 */
for (i=0; i<n; i++)
{
p = (Node *)malloc(sizeof(Node)); /* 生成新结点 */
p->data = rand()%100+1; /* 随机生成100以内的数字 */
r->next=p; /* 将表尾终端结点的指针指向新结点 */
r = p; /* 将当前的新结点定义为表尾终端结点 */
}
r->next = NULL; /* 表示当前链表结束 */
}
(2)获取链表第i个数据的算法思路:
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p; /* 声明一结点p */
p = L->next; /* 让p指向链表L的第一个结点 */
j = 1;
/* j为计数器 */
while (p && j<i) /* p不为空或者计数器j还没有等于i时,循环继续 */
{
p = p->next; /* 让p指向下一个结点 */
++j;
}
if ( !p || j>i )
return ERROR; /* 第i个元素不存在 */
*e = p->data; /* 取第i个元素的数据 */
return OK;
}
(3)单链表第i个数据插入结点的算法思路:
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while (p && j < i) /* 寻找第i个结点 */
{
p = p->next;
++j;
}
if (!p || j > i)
return ERROR; /* 第i个元素不存在 */
s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
(4)单链表第i个数据删除结点的算法思路:
Status ListDelete(LinkList *L,int i,ElemType *e)
{
int j;
LinkList p,q;
p = *L;
j = 1;
while (p->next && j < i)
/* 遍历寻找第i个元素 */
{
p = p->next;
++j;
}
if (!(p->next) || j > i)
return ERROR; /* 第i个元素不存在 */
q = p->next;
p->next = q->next;
/* 将q的后继赋值给p的后继 */
*e = q->data; /* 将q结点中的数据给e */
free(q); /* 让系统回收此结点,释放内存 */
return OK;
}
数据结构分为逻辑结构和物理结构。
逻辑结构分为:
集合结构:数据元素之间没有特别的关系,仅同属相同集合。
线性结构:数据元素之间是一对一的关系。
树形结构:数据元素之间存在一对多的层次关系。
图形结构:数据元素之间是多对多的关系。
物理结构分为:
顺序存储结构:将数据存储在地址连续的存储单元里。
链式存储结构:将数据存储在任意的存储单元里,通过保存地址的方式找到相关联的数据元素。
线性表的定义:
线性表(List)是零个或多个数据元素的集合。
线性表中的数据元素之间是有顺序的。
线性表中的数据元素个数是有限的。
线性表中的数据元素的类型必须相同。
性质:
a0为线性表的第一个元素只有一个后继。
an为线性表的最后一个元素,只有一个前驱。
除a0和an外的其他元素既有前驱又有后继。
线性表能够逐项访问和顺序存取。
2.顺序存储结构:线性表的顺序存储结构指的是用一段地址连续的存储单元依次存储线性表的数据元素。
(1)插入元素算法:
Status ListInsert(SqList *L,int i,ElemType e)
{
int k;
if (L->length==MAXSIZE) /* 顺序线性表已经满 */
return ERROR;
if (i<1 || i>L->length+1) /* 当i比第一位置小或者比最后一位置后一位置还要大时 */
return ERROR;
if (i<=L->length) /* 若插入数据位置不在表尾 */
{
for(k=L->length-1;k>=i-1;k--) /* 将要插入位置之后的数据元素向后移动一位 */
L->data[k+1]=L->data[k];
}
L->data[i-1]=e; /* 将新元素插入 */
L->length++;
return OK;
}
(2)删除元素算法:
Status ListDelete(SqList *L,int i,ElemType *e)
{
int k;
if (L->length==0) /* 线性表为空 */
return ERROR;
if (i<1 || i>L->length) /* 删除位置不正确 */
return ERROR;
*e=L->data[i-1];
if (i<L->length) /* 如果删除不是最后位置 */
{
for(k=i;k<L->length;k++) /* 将删除位置后继元素前移 */
L->data[k-1]=L->data[k];
}
L->length--;
return OK;
}
3.链式存储结构:
为了表示每个元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息。
链表的概念:
表头结点------链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息。
数据结点------链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息。
尾结点--------链表中的最后一个数据结点,其下一元素指针为空,表示无后继。
N个结点链接成一个链表,即为线性表(a1,a2,…an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫单链表。
链表中第一个结点的存储位置叫做头指针;最后一个结点指针为空(NULL)。
可在单链表的第一个结点前附设一个结点,称为头结点。可以不存储任何信息。
(1)单链表整表创建的算法思路:
void CreateListHead(LinkList *L, int n)
{
LinkList p;
int i;
srand(time(0)); /* 初始化随机数种子 */
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; /* 先建立一个带头结点的单链表 */
for (i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node)); /* 生成新结点 */
p->data = rand()%100+1; /* 随机生成100以内的数字 */
p->next = (*L)->next;
(*L)->next = p;
/* 插入到表头 */
}
}
上面那种叫做头插法,我们也可以通过尾插法来创建一个链表
void CreateListTail(LinkList *L, int n)
{
LinkList p,r;
int i;
srand(time(0)); /* 初始化随机数种子 */
*L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
r=*L; /* r为指向尾部的结点 */
for (i=0; i<n; i++)
{
p = (Node *)malloc(sizeof(Node)); /* 生成新结点 */
p->data = rand()%100+1; /* 随机生成100以内的数字 */
r->next=p; /* 将表尾终端结点的指针指向新结点 */
r = p; /* 将当前的新结点定义为表尾终端结点 */
}
r->next = NULL; /* 表示当前链表结束 */
}
(2)获取链表第i个数据的算法思路:
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p; /* 声明一结点p */
p = L->next; /* 让p指向链表L的第一个结点 */
j = 1;
/* j为计数器 */
while (p && j<i) /* p不为空或者计数器j还没有等于i时,循环继续 */
{
p = p->next; /* 让p指向下一个结点 */
++j;
}
if ( !p || j>i )
return ERROR; /* 第i个元素不存在 */
*e = p->data; /* 取第i个元素的数据 */
return OK;
}
(3)单链表第i个数据插入结点的算法思路:
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while (p && j < i) /* 寻找第i个结点 */
{
p = p->next;
++j;
}
if (!p || j > i)
return ERROR; /* 第i个元素不存在 */
s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
(4)单链表第i个数据删除结点的算法思路:
Status ListDelete(LinkList *L,int i,ElemType *e)
{
int j;
LinkList p,q;
p = *L;
j = 1;
while (p->next && j < i)
/* 遍历寻找第i个元素 */
{
p = p->next;
++j;
}
if (!(p->next) || j > i)
return ERROR; /* 第i个元素不存在 */
q = p->next;
p->next = q->next;
/* 将q的后继赋值给p的后继 */
*e = q->data; /* 将q结点中的数据给e */
free(q); /* 让系统回收此结点,释放内存 */
return OK;
}