2.1 顺序表
2.1.1 顺序表
线性表的顺序存储结构称为顺序表,指的是用一段地址连续的存储单元一次存储线性表的数据元素.
2.1.2 顺序表的实现
struct 和 typedef struct使用区别:点击打开链接
程序实例:
SeqList.h:
#ifndef SEQLIST_H
#define SEQLIST_H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int ElemType; //指用标识符ElemType代表int类型
typedef struct seqlist
{
ElemType *data_address; //存储空间首地址
int length; //当前长度
int size; //允许存储的最大容量
}seqlist; //别名顺序表
void Init(seqlist *L); //初始化函数
int Insert(seqlist *L,int pos,ElemType e); //按照位置插入
int Delete(seqlist *L,int pos); //按照位置删除
int Locate(seqlist *L,ElemType e); //按值查找
void PrintList(seqlist *L); //遍历操作
void Destroy(seqlist *L); //销毁
#endif
SeqList.c:
#include "SeqList.h"
const int MAXLISTSIZE=20; //预设的存储空间最大容量
/*初始化数组*/
void Init(seqlist *L)
{
printf("-------Start Init()--------\n");
L->data_address = (ElemType*)malloc(MAXLISTSIZE*sizeof(ElemType));
if(L->data_address == NULL) //内存分配失败,程序退出
{
exit(1);
}
L->size = MAXLISTSIZE;
L->length = 0;
printf("-------End Init()---------\n");
}
int Locate(seqlist *L,ElemType e)
{
int i = 1;
ElemType *p = L->data_address; //p的初值为第一个元素的存储位置
while(i<=L->length)
{
if(p[i]==e)
{
break;
}
i++;
}
if(i<=L->length)
{
return i;
}else{
return 0;
}
}
int Insert(seqlist *L,int pos,ElemType e)
{
int j;
if(pos < 1||pos >L->length+1) //插入位置不合法,合法位置是1~表长+1
{
printf("Insert Error pos\n");
return 0;
}
if(L->length>=L->size) //当前存储空间已满,无法插入
{
printf("Insert Error full of Store Space \n");
return 0;
}
for(j=L->length-1;j>=pos-1;--j)
{
L->data_address[j+1] = L->data_address[j]; //插入位置及之后的元素后移
}
L->data_address[pos-1] = e; //插入e
++L->length; //表长增加1
return 1;
}
int Delete(seqlist *L,int pos)
{
int i;
if(L->length == 0) //删除位置下溢
{
printf("Delete seqlist is Empty!");
return 0;
}
if(pos<1||pos>L->length) //删除位置不正确
{
printf("Delete pos is illegal!");
return 0;
}
for(i=pos;i<L->length;i++)
{
L->data_address[i-1] = L->data_address[i];
}
L->length--;
return 1;
}
void PrintList(seqlist *L)
{
int n,i;
n = L->length;
for(i=0;i<=n;i++)
{
printf("%6d\n",L->data_address[i]);
}
}
void Destory(seqlist *L)
{
free(L->data_address);
L->length = 0;
L->size = 0;
}
main.c:
#include <stdio.h>
#include "SeqList.h"
int main(void)
{
int i;
seqlist L;
ElemType e;
Init(&L);
srand((unsigned int)time(0));//srand(seed)用于给rand()函数设定种子
for(i=1;i<=10;i++)
{
Insert(&L,i,rand()%30); //插入10个元素
}
PrintList(&L);
printf("length:%d, Size:%d\n",L.length,L.size);
int j = Locate(&L,7);
if(j==0) //查找5所在的位置
{
printf("Not find 5 at the seqlist\n");
}else{
printf("Locate is : %d\n",j);
}
PrintList(&L);
Destory(&L);
return 0;
}
2.2单链表
2.2.1 单链表
单链表是用一组任意的存储单元存放线性表的元素,这组存储单元可以连续也可以不连续,甚至可以零散分布在内存中的任意位置.
节点示意图:
2.2.2 单链表的实现
LinkList.h:
#ifndef LINKLIST_H
#define LINKLIST_H
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node *next;
}Node,*LinkList; //Node 代表常规节点,LinkList代表链表及头节点
int Init(LinkList *L); //初始化
void CreateLinkListHead(LinkList *L,int n); //头插法创建单链表
void CreateLinkListTail(LinkList *L,int n); //尾插发创建单链表
int Insert(LinkList *L,int i,ElemType e); //在i位置插入元素e
int Delete(LinkList *L,int i,ElemType *e); //删除i位置元素
int Locate(LinkList *L,ElemType e); //按值查找
int ClearList(LinkList *L); //整表删除
void PrintList(LinkList *L); //遍历
#endif
LinkList.c:
#include "LinkList.h"
int Init(LinkList *L)
{
(*L) = (LinkList)malloc(sizeof(Node));
if(*L == NULL)
{
printf("Init LinkList Error");
return 0;
}
return 1;
}
void CreateLinkListHead(LinkList *L,int n)
{
Node *p;
int i;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL; //(*L)相当于头节点
for(i=0;i<n;i++)
{
p = (Node *)malloc(sizeof(Node)); //创建一个节点
p->data = rand()%100 + 1; //使用rand函数向节点添加内容
p->next = (*L)->next; //将节点添加上
(*L)->next = p;
}
}
void CreateLinkListTail(LinkList *L,int n)
{
Node *p,*r;
int i;
srand(time(0));
*L=(LinkList)malloc(sizeof(Node)); //头节点
r=*L;
for(i=0;i<n;i++)
{
p=(Node *)malloc(sizeof(Node));
p->data = rand()%100 +1;
r->next = p;
r=p; //r指针后移到p
}
r->next = NULL;
}
int Insert(LinkList *L,int i,ElemType e)
{
Node *p,*r;
int j=1;
r=(*L);
while(r&&j<i)
{
r=r->next;
++j;
}
if(!r || j>i)
{
return 0;
}
p=(Node *)malloc(sizeof(Node));
p->data = e;
p->next = r->next;
r->next = p;
return 1;
}
int Delete(LinkList *L,int i,ElemType *e)
{
int j;
Node *p,*q;
p= *L;
j=1;
//查找要删除的位置
while((p->next) && j<i)
{
p = p->next;
++j;
}
/*错误写法:会导致删除正确位置之后的一位
p= *L->next;
j=1;
//查找要删除的位置
while(p && j<i)
{
p = p->next;
++j;
}
*/
//判断删除位置是否合法
if(!(p->next) || j>i)
{
return 0;
}
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return 1;
}
int Locate(LinkList *L,ElemType e)
{
Node *p;
p=(*L)->next;
int i=1;
while(p)
{
if(p->data == e)
{
return i;
}
i++;
p=p->next;
}
return 0;
}
int ClearList(LinkList *L)
{
Node *p,*q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next = NULL;
return 1;
}
void PrintList(LinkList *L)
{
Node *p;
p=(*L)->next;
while(p)
{
printf(" %d ",p->data);
p=p->next;
}
printf("\n");
}
main.c
#include "LinkList.h"
int main(void)
{
// Node *L;
LinkList L;
int e;
//printf("%d\n",*L);
Init(&L);
//CreateLinkListHead(&L,10);
CreateLinkListTail(&L,10);
PrintList(&L);
Insert(&L,4,10);
PrintList(&L);
Delete(&L,4,&e);
printf("Delete:%d\n",e);
PrintList(&L);
printf("Locate:%d\n",Locate(&L,9));
PrintList(&L);
ClearList(&L);
PrintList(&L);
return 0;
}
2.3循环链表
2.3.1循环链表
将单链表中终端节点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为但循环链表,简称循环链表.
2.3.2原理
若使用尾指针,则查找开始节点和终端节点都很方便.如下:
2.4 双链表
2.4.1双链表
在循环链表中,虽然从任一节点出发可以扫描到其他节点,但要找到其前驱节点,则需要遍历整个循环链表.如果希望快速确定表中任一节点的前驱节点,可以在单链表的每个节点中再设置一个指向其前驱节点的指针域,这样就形成了双链表.
2.4.2原理
循环双链表的插入操作:
循环双链表删除操作:
2.5 静态链表
2.5.1 静态链表
静态链表是用数组来表示单链表,用数组元素的下标来模拟单链表的指针.
静态链表:给那些没有指针的高级语言设计的一种实现单链表能力的方法.