Skip to content

Commit

Permalink
完成双链表、循环链表、静态链表
Browse files Browse the repository at this point in the history
  • Loading branch information
happyflyer committed Nov 30, 2020
1 parent fc8d9fe commit 9511bbb
Show file tree
Hide file tree
Showing 8 changed files with 645 additions and 3 deletions.
39 changes: 36 additions & 3 deletions ch2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,41 @@ Tips:

- 缺点:无法逆向检索,有时候不太方便。

## 6. 双链表
## 6. [双链表](double-link/README.md)

## 7. 循环链表
### 6.1. 初始化

## 8. 静态链表
头结点 `prior``next` 都指向 `NULL`

### 6.2. 插入(后插)

- 注意新插入结点、前驱结点、后继结点的指针修改。
- 边界情况:新插入结点在最后一个位置,需特殊处理。

### 6.3. 删除(后删)

- 注意删除结点的前驱结点、后继结点的指针修改。
- 边界情况:如果被删除结点是最后一个数据结点,需特殊处理。

### 6.4. 遍历

- 从一个给定结点开始,后向遍历、前向遍历的实现(循环的终止条件)。
- 双链表不可随机存取,按位查找、按值查找都只能用遍历的方式实现。

## 7. [循环链表](circular-link/README.md)

- 如何判空
- 如何判断结点 `p` 是否是表尾、表头结点
- 如何在表头、表中、表尾插入、删除一个结点

## 8. [静态链表](static-link/README.md)

用数组的方式实现的链表。

- 优点:增、删操作不需要大量移动元素。
- 缺点:不能随机存取,只能从头结点开始一次往后查找,容量固定不可变。

适用场景:

- 不支持指针的低级语言。
- 数据元素数量固定不变的场景(如操作系统的文件分配表 FAT)。
141 changes: 141 additions & 0 deletions ch2/circular-link/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# 循环链表

## 1. 循环单链表

### 1.1. 定义

- 单链表:表尾结点的 `next` 指针指向 `NULL`
- 循环单链表:表尾结点的 `next` 指针指向头结点。

```cpp
typedef struct LNode
{
int data;
struct LNode *next;
} LNode, *LinkList;
```

```cpp
// 初始化一个循环单链表,带头结点,头结点不存储数据
bool InitList(LinkList &L)
{
// 分配一个头结点
L = (LNode *)malloc(sizeof(LNode));
if (L == NULL)
{
return false;
}
L->next = L;
return true;
}
```
```cpp
// 判断循环单链表是否为空
bool Empty(LinkList L)
{
return L->next == L;
}
```

```cpp
// 判断 p 结点是否为表尾结点
bool isTail(LinkList L, LNode *p)
{
return p->next == L;
}
```
### 1.2. 特性
- 单链表:从一个结点出发,只能找到后续的各个结点。
- 循环单链表:从一个结点出发,可以找到其他任何一个结点。
如果经常操作循环单链表的头部或尾部,可以让 `L` 指向表尾结点。
- 单链表和循环单链表:从头结点找到尾部,时间复杂度为 $O(n)$。
- 循环单链表:从尾部找到头部,时间复杂度为 $O(1)$。
> 插入、删除时需要修改 L。
## 2. 循环双链表
### 2.1. 定义
- 双链表:表头结点的 `prior` 指向 `NULL`,表尾结点的 `next` 指向 `NULL`。
- 循环双链表:表头结点的 `prior` 指向表尾结点,表尾结点的 `next` 指向表头结点。
```cpp
typedef struct DNode
{
int data;
struct DNode *prior, *next;
} DNode, *DLinkList;
```

```cpp
// 初始化一个循环双链表,带头结点
bool InitDLinkList(DLinkList &L)
{
L = (DNode *)malloc(sizeof(DNode));
if (L == NULL)
{
return false;
}
L->prior = L;
L->next = L;
return true;
}
```
```cpp
// 判断双链表是否为空
bool Empty(DLinkList L)
{
return L->next == L;
}
```

```cpp
// 判断 p 结点是否为表尾结点
bool isTail(DLinkList L, DNode *p)
{
return p->next == L;
}
```
### 2.2. 后插
```cpp
// 后插操作:在 p 结点之后插入 s 结点
bool InsertNextDNode(DNode *p, DNode *s)
{
if (p == NULL || s == NULL)
{
return false;
}
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
return true;
}
```

### 2.3. 后删

```cpp
// 删除操作:删除 p 结点的后继结点 q
bool DeleteNextDNode(DLinkList L, DNode *p)
{
if (p == NULL || isTail(L, p))
{
return false;
}
DNode *q = p->next;
p->next = q->next;
q->next->prior = p;
free(q);
return true;
}
```
67 changes: 67 additions & 0 deletions ch2/circular-link/double.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct DNode
{
int data;
struct DNode *prior, *next;
} DNode, *DLinkList;

// 初始化一个循环双链表,带头结点
bool InitDLinkList(DLinkList &L)
{
L = (DNode *)malloc(sizeof(DNode));
if (L == NULL)
{
return false;
}
L->prior = L;
L->next = L;
return true;
}

// 判断双链表是否为空
bool Empty(DLinkList L)
{
return L->next == L;
}

// 判断 p 结点是否为表尾结点
bool isTail(DLinkList L, DNode *p)
{
return p->next == L;
}

// 后插操作:在 p 结点之后插入 s 结点
bool InsertNextDNode(DNode *p, DNode *s)
{
if (p == NULL || s == NULL)
{
return false;
}
s->next = p->next;
p->next->prior = s;
s->prior = p;
p->next = s;
return true;
}

// 删除操作:删除 p 结点的后继结点 q
bool DeleteNextDNode(DLinkList L, DNode *p)
{
if (p == NULL || isTail(L, p))
{
return false;
}
DNode *q = p->next;
p->next = q->next;
q->next->prior = p;
free(q);
return true;
}

int main()
{
DLinkList L;
InitDLinkList(L);
return 0;
}
39 changes: 39 additions & 0 deletions ch2/circular-link/single.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
} LNode, *LinkList;

// 初始化一个循环单链表,带头结点,头结点不存储数据
bool InitList(LinkList &L)
{
// 分配一个头结点
L = (LNode *)malloc(sizeof(LNode));
if (L == NULL)
{
return false;
}
L->next = L;
return true;
}

// 判断循环单链表是否为空
bool Empty(LinkList L)
{
return L->next == L;
}

// 判断 p 结点是否为表尾结点
bool isTail(LinkList L, LNode *p)
{
return p->next == L;
}

int main()
{
LinkList L;
InitList(L);
return 0;
}
Loading

0 comments on commit 9511bbb

Please sign in to comment.