考研笔记之数据结构之线性表(严蔚敏版)
Posted 啊~小 l i
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考研笔记之数据结构之线性表(严蔚敏版)相关的知识,希望对你有一定的参考价值。
顺序表的定义
- 顺序表的特点为表中元素的逻辑顺序与物理顺序相同。
- sizeof(数据类型):数据元素所占用的存储空间的大小
- 起始位置为LOC(A),第i个元素为LOC(A)+(n-1)*sizeof(数据类型)
线性表的初始化
静态分配
- 使用静态数组
- 大小确定无法改变
#define MaxSize 10
typedef struct
ElemType data[MaxSize];
int length;
mystruct;
ElemType:是一个抽象的数据类型,表示我们想使用的所有数据类型。(编写程序不能直接使用哦!)
代码实现
# include<stdio.h>
# define maxSize 10 // 定义最大长度
typedef struct
int data[maxSize]; // 使用静态数组存储元素
int lenth; // 顺序表的当前长度
sqList; // 顺序表类型定义
void initList(sqList &L)
for (int i = 0; i < maxSize; i++) //设置所有元数组素初始值(这里的括号可以去掉)
L.data[i] == 0; //定义初始长度
L.lenth = 0;
int main()
sqList L; //生成一个顺序表
initList(L); //初始化顺序表
return 0;
如果数组满了,顺序表的表长确定,数组空间确定(存储空间是静态的)
动态分配
- 使用“动态数组”
- L.data=(ElemType *)malloc(sizeof(ElemType)*initSize);
- 顺序表满时可以使用malloc动态扩展存储的最大容量
- 需要元素复制到新的存储区域,并用free函数释放原区域
# define initSize 10 //初始长度
typedef struct
ElemType* data; //动态分配数组指针
int maxSize; //最大容量
int length; // 当前长度
sqList; // 类型的定义
PS:
—malloc、free函数—
L.data=(ElemType *)malloc(sizeof(ElemType)*initSize)
``
代码实现
# include<stdio.h>
#include <stdlib.h> // 使用malloc、free函数需要引用头文件
# define initSize 10 // 默认最大长度
typedef struct
int * data;
int maxSize;
int length;
sqList;
void initList(sqList& L)
L.data = (int*)malloc(initSize * sizeof(int));//用malloc函数申请一篇连续的空间
L.length = 0;
L.maxSize = initSize;
void increaseSize(sqList& L, int len)
int* p = L.data;
L.data = (int*)malloc((L.maxSize + len) * sizeof(int));
for (int i = 0; i < L.length; i++)
L.data[i] = p[i];
L.maxSize = L.maxSize + len;
free(p);
int main()
sqList L; //声明一个顺序表
initList(L); //初始化顺序表
increaseSize(L, 5);
return 0;
顺序表的特点:
- 随机访问,在O(1)内找到第i个元素
- 存储密度高,每个节点只存储数据元素
- 扩展不方便(采用动态分配的方式实现扩展时间复杂度也比较高)
- 插入、删除不方便需要移动大量的元素
顺序表的按位查找
静态分配
# define maxSize 10
typedef struct
ElemType data[maxSize];
int length;
sqList;
ElemType getElem(sqList L, int i)
return L.data[i - 1];
动态分配
# define initSize 10
typedef struct
ElemType* data;
int MaxSize;
int length;
sqList;
Elemtype getElem(sqList L, int i)
return L.data[i - 1];
按值查找
// 按值查找(返回数组下标)
int localElem(sqList L, int e)
for (int i = 0; i < L.length; i++)
if (L.data[i] == e)
return i + 1;
return 0; //没有找到返回0
PS: 结构类型相同的比较不能直接使用等号,需要分别对结构体中的每一个元素进行比较
时间复杂度:
- 最好的结果O(1):出现在顺序表第一个位置
- 最坏的结果O(n):出现在顺序表最后一个位置
- 平均的结果O((n+1)/n):出现在每一个位置的概率相等
附全代码
# include<stdio.h>
# include <stdlib.h>
# define initSize 10
typedef struct
int * data;
int maxSize;
int length;
sqList;
void initList(sqList& L)
L.data = (int*)malloc(initSize * sizeof(int));
L.length = 0;
L.maxSize = initSize;
void increaseSize(sqList& L, int len)
int* p = L.data;
L.data = (int*)malloc((L.maxSize + len) * sizeof(int));
for (int i = 0; i < L.length; i++)
L.data[i] = p[i];
L.maxSize = L.maxSize + len;
free(p);
// 按位查找
int getElem(sqList L, int i)
return L.data[i - 1];
// 按值查找(返回数组下标)
int localElem(sqList L, int e)
for (int i = 0; i < L.length; i++)
if (L.data[i] == e)
return i + 1;
return 0;
int main()
sqList L;
initList(L);
increaseSize(L, 5);
return 0;
链表
单链表的定义:通过一组任意的存储单元来存储线性表中的数据元素。(除了存储自身信息外还需要存储指向后继的指针)
链表的建立
# include<stdio.h>
# include <stdlib.h>
typedef struct LNode // 定义单链表节点类型
ElemType data; // 每个节点存放一个数据类型
struct LNode* next; //指针指向下一个节点
LNode,*linkList;
// 等价于
struct LNode
ElemType data;
struct LNode* next;
;
typedef struct LNode LNode; //将结构体重命名为LNode
typedef struct LNode *linklist; //表示指向struct LNode的指针(将结构体指针重命名为linkList)
//声明头指针
LNode* L;
// 或
linkList* L;
理解:
- LNode是一个具象的结构体,指向的是包含某个数据类型的数据域和指针域的结构体类型
- LinkList是LNode的指针类型,它占用一定的内存空间,内存空间中的值位一个LNode类型结构体的地址
声明一个不带头节点的单链表
typedef struct LNode // 定义单链表节点类型
int data; // 每个节点存放一个int类型
struct LNode* next; //指针指向下一个节点
LNode,*linkList;
bool initList(linkList& L)
L = NULL; //空表无任何节点
return true;
// 判断单链表是否为空
bool Empty(linkList L)
if (L == NULL)
return true;
else
return false;
int main()
linkList L; //初始化空表
initList(L);
return 0;
带头节点的单链表
# include<stdio.h>
# include <stdlib.h>
typedef struct LNode // 定义单链表节点类型
int data; // 每个节点存放一个int类型
struct LNode* next; //指针指向下一个节点
LNode,*linkList;
// 初始化一个单链表
bool initList(linkList& L)
L = (LNode*)malloc(sizeof(LNode));
if (L==NULL)
return false;
L->next = NULL;
return true;
int main()
linkList L;
initList(L);
return 0;
链表的插入
带头节点按位序插入
最后插入新的结点的顺序不能颠倒
typedef struct LNode // 定义单链表节点类型
int data; // 每个节点存放一个int类型
struct LNode* next; //指针指向下一个节点
LNode,*LinkList;
// 中间插入
bool ListInsert(LinkList& L, int i, int e)
if (i<1) //判断插入的位置是否合适
return false;
LNode* p; //指针p指向当前扫描到的结点
int j = 0; //p指向第几个结点
p = L;
while (p!=NULL && j<i-1) //循环到i-1个节点 (找到i-1个结点)
p = p->next;
j++;
if (p == NULL) //i的值不合法,超出了插入的范围(i-1)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
后插操作:
// 后插(在某个结点后插入一个结点)
bool InsertNextNode(LNode* p, int e)
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (s == NULL)
printf("分配失败");
s->data = e;
s->next = p->next;
p->next = s;
return true;
前插操作:
// 前插操作(偷天换日) 原理:使用尾插法在后面插入一个新的结点
// 然后将前一个结点的data放到新结点,然后将要插入的数据放到p中
bool InsertPriNode(LNode* p, int e)
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
if (s==NULL)
return false;
s->next = p->next;
p->next = s; // 将新结点s连接到p之后
s->data = p->data; //将P中的元素,复制到s中
p->data = e; // 将p中的元素覆盖为e
return true;
// 王道书的版本
bool insertPrinorNode(LNode* p, LNode* s)
if (p==NULL||s==NULL)
return false;
s->next = p->next;
p->next = s;
int tep = p->data;
p->data = s->data;
s->data = tep;
return true;
删除操作:
// 按位序删除
bool ListDelete(LinkList& L, int i, int e)
if (i < 1)
return false;
LNode* p; // 当前指针所在的结点位置
int j = 0; //指向第几个结点
p = L; //指向头结点,第0个(无数据)
while (p!=NULL&&j<i-1) //循环到第i-1个(找到删除结点的前驱结点)
p = p->next;
j++;
if (p == NULL) //i的值不合法
return false;
if (p->next == NULL) //第i-1个结点之后无其他按结点
return false;
LNode* q = p->next; //令q指向被删除的结点
e = q->data; //用e返回删除的值
free(p); // 释放存储空间
return true; // 删除成功
//删除指定结点p(无法删除链表的最后一个元素)
bool DeleteNode(LNode* p)
if (p == NULL)
return false;
LNode* q = p->next;
q->data = p->next->data;
p->next = q->next;
free(q);
return true;
不带头结点的插入
相比于带头节点的来说,需要多谢一块代码来处理第一个结点的删除
bool ListInsert(LinkList& L, int i, int e)
if (i<1) //判断插入的位置是否合适
return false;
if (i == 1)
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next=L;
L = s;
return true;
LNode* p; //指针p指向当前扫描到的结点
int j = 0; //p指向第几个结点
p = L;
while (p!=NULL && j<i-1) //循环到i-1个节点
p = p->next;
j++;
if (p == NULL) //i的值不合法,超出了插入的范围(i-1)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
小结:
- 空表的判断:
- 不带头结点:L==NULL
- 带头节点:L->next == NULL
- 区别LNode和LinkList
- LNode强调这是节点
- LinkList强调这是链表
以上是关于考研笔记之数据结构之线性表(严蔚敏版)的主要内容,如果未能解决你的问题,请参考以下文章