开发环境
window10
visual studio 2019
c
1 线性表的特点
(1)表中元素个数有限
(2)表中元素具有逻辑上的顺序性,表中元素有其先后次序
(3)表中元素都是数据元素,每个元素都是单个元素
(4)表中元素的数据类型都相同,这意味着每个元素占有相同大小的存储空间
(5)表中元素具有抽象性,即仅讨论元素见的逻辑关系,而不考虑元素究竟表示什么内容
2 线性表的存储结构
#define MAXSIZE 50 //定义线性表的最大长度
#define true 1
#define false 0
2.1 顺序存储
2.1.1 静态分配存储空间
typedef struct {
ElemType data[MAXSIZE]; //顺序表的元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义
2.1.2 动态分配存储空间
typedef struct {
ElemType* data; //顺序表的元素
int Maxsize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList;
2.1.3 顺序表的基本操作
对动态分配空间的线性表进行操作定义
void InitList(SeqList* L);
int Length(SeqList L);
int LocateElem(SeqList L,ElemType e);
int GetElem(SeqList L,int i);
_Bool ListInsert(SeqList* L, int i, ElemType e);
_Bool ListDelete(SeqList* L, int i, ElemType* e);
void PrintList(SeqList L);
_Bool Empty(SeqList L);
_Bool DestroyList(SeqList* L);
void main() {
SeqList* L = (SeqList*)malloc(sizeof(SeqList) * MAXSIZE); //解决error:C4700错误,初始化局部变量
InitList(L);
······
}
(1) 初始化表
构造一个空的线性表
void InitList(SeqList* L){
L->data = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE);
L->Maxsize = MAXSIZE;
L->length = 0;
}
(2) 求表长
返回线性表L的长度,即L中数据元素的个数
int Length(SeqList L) {
return L.length;
}
(3) 按值查找操作
按值查找操作。在表L中查找具有给定关键字值的元素
int LocateElem(SeqList L,ElemType e) {
int i;
for (i = 0; i < L.length; i++)
if (L.data[i] == e)
return i+1; //下标为i的元素值等于e,返回其位序i+1
return false; //退出循环,说明查找失败
}
(4) 按位查找操作
按位查找操作。获取表L中得第i个位置的元素的值
int GetElem(SeqList L,int i) {
if (i < 1 || i > L.length)
return false;
return L.data[i];
}
(5) 插入操作
在表L中的第i个位置(1<=i<=L.length+1)上插入指定元素e
_Bool ListInsert(SeqList* L, int i, ElemType e) {
//判断合法性
if (i < 1 || i > L->length + 1)
return false; //判断i的范围是否有效
if (L->length >= L->Maxsize)
return false; //当前存储空间已满,不能插入
//插入元素
int j;
for (j = L->length; j >= i; j--)
L->data[j] = L->data[j - 1]; //将第i个元素及之后的元素后移
L->data[i - 1] = e; //在位置i处放入e
L->length++; //线性表长度+1
return true;
}
(6) 删除操作
删除表L中的第i个(1<=i<=L.length)位置的元素,并用e返回删除元素的值
_Bool ListDelete(SeqList* L, int i, ElemType* e) {
//判断合法性
if (i < 1 || i > L->length)
return false; //判断i的范围是否有效
e = L->data[i-1]; //将被删除的元素赋值给e
//删除元素
int j;
for (j = i; j < L->length; j++)
L->data[j - 1] = L->data[j]; //将第i个位置后的元素前移
L->length--; //线性表长度-1
return false;
}
(7) 输出操作
按前后顺序输出线性表L的所有元素值
void PrintList(SeqList L) {
int i;
for (i = 0; i < L.length; i++)
printf("%d\t", L.data[i]);
printf("\n");
}
(8) 判空操作
若L为空表,则返回true,否则返回false
_Bool Empty(SeqList L) {
if (L.length <= 0)
return true;
return false;
}
(9) 销毁操作
销毁线性表,并释放线性表L所占用的内存空间
_Bool DestroyList(SeqList* L) {
if (L != NULL)
free(L);
else
return false;
L = NULL;
return true;
}
2.2 链式存储
2.2.1 单链表及其基本操作
#define MAXSIZE 50 //定义线性表的最大长度
#define true 1
#define false 0
typedef int ElemType; //定义线性表的元素类型
typedef struct LNode {
//定义单链表结点类型
ElemType data; //数据域
struct LNode* next; //指针域
}LNode, * LinkList;
LinkList List_HeadInsert(LinkList L);
LinkList List_TailInsert(LinkList L);
LNode* GetElem(LinkList L, int i);
LNode* LocateElem(LinkList L, ElemType e);
_Bool ListInsertAfter(LinkList L, int i, ElemType e);
_Bool ListInsertFront(LinkList L, int i, ElemType e);
_Bool ListDeletePos(LinkList L, int i, ElemType e);
_Bool ListDeleteNode(LinkList L, LNode* p, ElemType e);
void PrintList(LinkList L);
_Bool DestroyList(LinkList L);
_Bool Empty(LinkList L);
void main() {
LinkList L = NULL;
······;
}
(1)建立单链表
(1.1)头插法建立单链表
从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后。
LinkList List_HeadInsert(LinkList L) {
//头插法,逆向建立单链表
LNode* s;
ElemType x;
L = (LinkList)malloc(sizeof(LNode)); //创建链表/头结点
L->next = NULL; //初始为空
scanf_s("%d", &x); //引用:取地址
while (x != 9999) {
//输入9999表示结束
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
s->next = L->next;
L->next = s; //将新结点插入表中,L为头指针
scanf_s("%d",&x);
}
return L;
}
(1.2)尾插法建立单链表
将新结点插入到当前链表的表尾,为此必须增加一个尾指针tail,使其始终指向当前链表的尾结点。
LinkList List_TailInsert(LinkList L) {
//尾插法,正向建立单链表
LNode* s;
ElemType x;
L = (LinkList)malloc(sizeof(LNode)); //创建链表
LNode* tail = L; //创建尾结点
scanf_s("%d", &x); //引用:取地址
while (x != 9999) {
//输入9999表示结束
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = x;
tail->next = s;
tail = s; //将新结点插入表中,L为头指针
scanf_s("%d", &x);
}
tail->next = NULL; //为空
return L;
}
(2)查找结点值
(2.1)按序号
从第一个结点出发,顺指针next域逐个往下搜索,直到找到第i个结点为止,否则放回最后一个结点指针域NULL。
LNode* GetElem(LinkList L, int i) {
int count = 1; //计数,初始为1
LNode* p = L->next; //头结点指针赋给p
if (i == 0)
return L; //若i等于0,则返回头结点
if (i < 1)
return NULL; //若i无效,则返回NULL
while (p && count < i) {
//从第1个结点开始找,查找第i个结点
p = p->next;
count++;
}
return p; //返回第i个结点的指针,若i大于表长则返回NULL
}
(2.1)按值
从第一个结点开始,由前往后依次比较表中各结点数据域的值,若某结点数据域的值等于给定值e,则返回该结点的指针;若整个表中没有这样的结点,则返回NULL。
LNode* LocateElem(LinkList L, ElemType e) {
LNode* p = L->next;
while (p != NULL && p->data != e) //从第1个结点开始查找data域为e的结点
p = p->next;
return p; //找到后返回该结点指针,否则返回NULL
}
(3)插入结点操作
(3.1)后插
将值为x的新结点插入到单链表的第i个位置上
_Bool ListInsertAfter(LinkList L, int i, ElemType e) {
LNode* s;
LNode* p;
if (!(p = GetElem(L, i - 1))) //查找插入位置的前驱结点
return false;
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
(3.2)前插
将值为x的新结点插入到单链表的第i个位置结点的前面
_Bool ListInsertFront(LinkList L, int i, ElemType e) {
LNode* s;
LNode* p;
ElemType temp;
if (!(p = GetElem(L, i - 1)))
return false;
s = (LNode*)malloc(sizeof(LNode)); //创建新结点
s->data = e;
s->next = p->next;
p->next = s;
/*交换数据域*/
temp = p->data;
p->data = s->data;
s->data = temp;
return true;
}
(4)删除结点操作
(4.1)按位置
将单链表的第i个结点删除
_Bool ListDeletePos(LinkList L, int i, ElemType e) {
LNode* p;
LNode* q;
if (!(p = GetElem(L, i - 1))) //查找删除位置的前驱结点
return false;
q = p->next; //令q指向被删除结点
p->next = q->next; //将*q结点从链中“断开”
e = q->data;
free(q); //释放结点的存储空间
return true;
}
(4.2)按结点
将单链表的指定结点删除
_Bool ListDeleteNode(LinkList L, LNode* p, ElemType e) {
if (p == NULL)
return false;
LNode* q;
q = p->next; //令q指向*p的后继结点
e = q->data;
p->data = q->data; //和后继结点交换数据域
p->next = q->next; //将*q结点从链中“断开”
free(q); //释放后继结点的存储空间
return true;
}
(5)求表长操作
int Length(LinkList L) {
int count = 0;
LNode* p = L;
while (p->next != NULL) {
count++;
p = p->next;
}
return count;
}
(6)打印表操作
void PrintList(LinkList L) {
LNode* p = L;
p = p->next;
while (p != NULL) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
printf("链表长度:%d\n", Length(L));
}
(7)销毁表操作
_Bool DestroyList(LinkList L) {
if (!L)
return false;
while (L) {
LNode* p;
p = L;
L = L->next;
free(p);
}
return true;
}
(8)判空操作
_Bool Empty(LinkList L) {
if (!L)
return true;
return false;
}
2.2.2 双链表
(1)双链表定义
typedef struct DNode {
//定义双链表结点类型
ElemType data; //数据域
struct DNode* prior, * next; //前驱和后继指针
}DNode,* DLinkList;
(2)插入
在结点p后插入结点s
s->next = p->next;
s->prior = p;
p->next->prior = s;
p->next = s;
(3)删除
删除结点s,p指向结点s的前驱结点
p = s->prior;
p->next = s->next;
s->next->prior = p;
free(s);
2.2.3 循环链表
(1)循环单链表
尾结点甩回头结点。
(2)循环双链表
尾结点后继指针甩回头结点,头结点前驱指针指向尾结点。
2.2.4 静态链表
typedef struct{
//静态链表结构类型的定义
ElemType data; //存储数据元素
int next; //下一个元素的数组下标
}SLinkList[MAXSIZE];
3 参考
王道,侵删