链表是一种线性结构,在存储数据时,在逻辑上是连续的,但是在物理空间上并不连续。
一个链表的结点由两个部分组成,分别是数据域和指针域。
而单链表就是它的每一个结点,除了记录元素的数据外,只记录其直接后继结点的地址。
单链表由两种实现方法:
- 头结点实现
- 头指针实现
头结点单链表的基本操作
头结点单链表的数据结构
typedef int ElemType;
typedef struct Node {
ElemType data;
struct Node *next;
}HeadList;
头结点的初始化
头结点的初始化只需把头结点的next指针域置空即可。
void InitHeadList(HeadList* head)
{
if (head == NULL) exit(0);
head->next = NULL;
}
插入新结点
单链表插入新结点的逻辑如上图。
先找到插入位置的前一个结点p,然后申请一个新结点,然后就是:
- s->next = p ->next;
- p->next = s;
需要注意:这两步先后顺序不可改变。
头插法插入新结点
思路:
- 申请一个新结点,并把新结点的next指针指向头结点的后继节点
- 最后把头结点的next指针指向新结点
- 插入成功
bool InsertOFHead(HeadList* head, ElemType val)
{
if (head == NULL) exit(0);
if (pos < 0) return false;
HeadList* newNode = ApplyNode(val, head->next);
if (newNode == NULL) return false;
head->next = newNode;
return true;
}
尾插法插入新结点
思路:
- 先声明一个结点类型的指针p指向头结点
- 把p指针后置,一直到指向最后一个结点,也就是p所指向的结点的后继为空
- 申请一个新结点并把指针域置空,把p的后继指向新结点
- 插入成功
bool InsertOFTail(HeadList* head, ElemType val)
{
if (head == NULL) exit(0);
HeadList* p = head;
while (p->next != NULL) p = p->next;
p->next = ApplyNode(val, NULL);
return true;
}
按位置插入新结点
思路:
- 先声明一个结点类型的指针p指向头结点
- p向后迭代,迭代的过程中,迭代一次插入的位置也随之减1
- 如果p为空,则插入的位置大于链表的长度,插入失败
- 如果插入的位置存在,申请一个新结点,新结点的指针域指向p的next指向的结点
- 把p的next指针指向新结点
- 插入成功
bool InsertOFPos(HeadList* head, ElemType val, int pos)
{
if (head == NULL) exit(0);
if (pos < 0) return false;
HeadList* p = head;
while (pos && p != NULL)
{
pos--; p = p->next;
}
if (p == NULL) return false;
HeadList* newNode = ApplyNode(val, p->next);
if (newNode == NULL) return false;
p->next = newNode; return true;
}
删除节点
单链表删除新结点的逻辑如上图。
先找到删除节点的前一个结点p的位置,q为要删除的结点,然后把p->next = q->next;
,然后释放删除的结点即可完成删除。
头删
思路:
- 声明一个结点类型的指针q,q指向头结点next指向的结点
- 把头结点的next域指向q指向结点的next域
- 释放q指向的结点
- 删除成功
bool DeleteOFPos(HeadList* head)
{
if (head == NULL) exit(0);
HeadList *q = head->next;
head->next = q->next;
free(q);
return true;
}
尾删
思路:
- 声明两个指针p、q,p指向头结点,q指向头结点的下一个结点
- 把p和q一起迭代,直到q的next为空
- 把p的next置空
- 释放q
- 删除完成
bool DeleteOFTail(HeadList * head)
{
if (head == NULL) exit(0);
if (head->next == NULL) return false;
HeadList * p = head, *q = head->next;
while (q->next != NULL)
{
p = q;
q = q->next;
}
p->next = NULL;
free(q);
return true;
}
按位置删
思路:
- 先声明一个结点类型的指针p指向头结点
- p向后迭代,迭代的过程中,迭代一次插入的位置也随之减1
- 迭代结束如果p的next为空,删除位置没有元素,删除失败
- 如果删除的位置存在元素,声明一个结点类型的指针q指向删除位置的元素
- 把p->next = q->next;
- 释放q指向的结点
- 删除完成
bool DeleteOFPos(HeadList* head, int pos)
{
if (head == NULL) exit(0);
HeadList * p = head;
while (pos && p->next != NULL)
{
pos--;
p = p->next;
}
if (p->next == NULL) return false;
HeadList * q = p->next;
p->next = q->next;
free(q);
return true;
}
头指针单链表的基本操作
头指针单链表的实现和头结点单链表的实现几乎一致。
和头结点单链表实现的区别: 插入时为空链的特殊处理和删除第一个结点的特殊处理。