目录
前言
介绍数据结构和算法中最基础的一种数据结构:线性表
定义
线性表:零个或者多个数据元素的有限序列。
强调定义中两个关键的点:
- 序列:元素之间是有序的,如果元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每一个元素都有且只有一个前驱和后继。
- 有限:计算机中处理的对象是有限的。
线性表常见操作
- 初始化
- 清空
- 查找
- 长度
- 插入
- 删除
线性表的顺序存储结构
定义
指的是用一段地址连续的存储单元依次存储线性表的数据元素。
顺序存储结构代码
#define MAXSIZE 20 // 存储空间初始化分配量
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];
int lenght; /*线性表的当前长度*/
}Sqlist;
顺序存储结构需要三个属性:
- 存储空间的起始位置:数组data,它的存储位置就是存储空间的起始位置
- 线性表的最大存储容量。
- 线性表的当前长度。
线性表的链式存储结构
头指针和头节点的异同
在链式存储结构中会涉及到头指针和头节点的概念。
头指针:指向链表第一个节点的指针,若链表有头结点,则是指向头结点的指针。头指针具有标识作用,所以常用头指针冠以链表的名字。无论链表是否为空,头指针均不为空,头指针是链表的必要元素。
头结点:一般命名为DummyNode,是为了操作的统一和方便设立的,放在第一元素的节点之前。其数据域一般无意义(也可以存放链表的长度)。有了头结点,对在第一元素节点前插入节点和删除第一节点,其操作和其他节点的操作就统一了。头节点不一定是链表的必要元素。
链式存储结构代码
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node* LinkedList;
常见操作代码,建议记忆
读取节点
// 单链表的读取
Satus GetElement(LinkedList L,int i, ElemType *e)
{
int j;
LinkedList p; // 声明一个节点p
p = L; // L为头指针
j = 1; // j为计数器
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return ERROR;
}
*e = p->data;
return OK;
}
插入节点
// 单链表插入标准语句:s->next = p->next; p->next = s;
Status ListInsert (LinkedLsit L,int i, ElemetType e)
{
int j; // 计数器
LinkedList p,s
p = L;
j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return ERROR;
}
s = malloc(sizeof (Node));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
删除某个节点
// 单链表删除标准语句:q = p->next; p->next = q->next;
Status ListDelet(LinkedList L, int i,ElemType* e)
{
int j; // 计数器
LinkedList p ,q;
p = L; // L为头指针
j = 1;
while (p && j < i - 1)
{
p = p->next;
j++;
}
if (!p || j > i - 1)
{
return ERROR;
}
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
创建整个链表
// 头插
/*
标准语句:
loop
{
p = malloc();
p->next = L->next;
L->next = p;
}
*/
void CreatListHead(LinkedList L, int n)
{
LinkedList p;
int i;
L = malloc(sizeof(Node)); // 创建头结点
L->next = NULL;
for( i = 0; i < n ; i++)
{
p = malloc(sizeof (Node)); // 生成新节点
p->data = rand() % 100;
p->next = L->next;
L->next = p; // 插入到表头
}
}
// 尾插
/*
标准语句
loop
{
p = malloc(); // 生成新的节点
r->next = p;
r = p;
}
*/
void CreatListTail(LinkedList L, int n)
{
LinkedList p , r;
int i;
L= malloc(sizeof (Node));
r = L;
for (i = 0;i < n; i++)
{
p = malloc(sizeof (Node));
p->data = rand() % 100;
r->next = p;
r = p;
}
r->next = NULL;
}
删除整个链表
/*
标准语句
q = p->next; // 在释放p之前,一定要先将他的后继节点找到
free(p);
p = q;
*/
Status ClearList(LinkedList L)
{
LinkdeList p ,q
p = L; // L为头指针
while (p)
{
q = p->next;
free(p);
p = q;
}
}
链式结构和顺序结构的优缺点对比——建议记忆
- 存储分配方式
顺序存储结构用一段连续的存储单元存储数据元素
链表采用链式存储结构,存储单元不是连续的。 - 时间性能
查找
顺序存储结构:O(1)
链表 O(n)
插入&删除:
顺序存储结构:O(n)
链表:O(1) - 空间性能
顺序存储需要预分配存储空间
链表不需要预分配存储空间。