一、概念
1、链表:逻辑上连续,物理存储不连续的一种线性表的实现,链表具有唯一的起始和唯一的结尾
2、单链表:前一个结点除了存储元素值外,还必须存储下一个结点的地址
除了最后一个元素外,每一个结点都有一个直接后继
3、头指针:链表中第一个结点的存储位置叫做头指针
4、头结点:在单链表的第一个结点前附设一个结点,称为头结点
头结点的数据域可以不存储任何信息,头结点的指针域存储指向第一个结点的指针
- 头指针与头结点的异同
头指针 | 头结点 |
|
|
|
|
|
|
二、单链表(带头结点)
1、存储结构
typedef int ElemType;
typedef struct Node
{
ElemType data; //数据域:存储数据
struct Node* next; //指针域:存储下一个结点的地址
}Node,*pList;
2、初始化
void init(pList phead)
{
if (phead == nullptr)
{
exit(0);
}
phead->next = nullptr;
}
3、插入
- 单链表中插入一个结点,首先先要购买一个结点作为要插入的结点
购买结点
Node* buyNode(ElemType val)
{
Node* pnewnode = (Node*)malloc(sizeof(Node));
pnewnode->data = val;
pnewnode->next = nullptr;
return pnewnode;
}
- 插入时要注意语句的先后顺序
(先将插入结点的后继指向插入结点前一个结点的后继,再将前一个结点的后继指向插入结点)
(1)头插
int insertHead(pList phead, ElemType val)
{
/*
return insertPos(phead, 0, val);
*/
//一般来说都要先进行判空
Node* pnewnode = buyNode(val);//先购买结点
pnewnode->next = phead->next;//新结点的指针域指向头结点之后的数据
phead->next = pnewnode; //头结点的指针域指向新结点
return 1; //成功
}
(2)尾插
int insertTali(pList phead, ElemType val)//新结点放到最后一个结点之后--》先找尾部结点
{
Node* pnewnode = buyNode(val);
Node* ptail = phead;
while (ptail->next != NULL)
{
ptail = ptail->next;
}
ptail->next = pnewnode;//将新结点的地址写到尾结点的指针域(尾结点指向的新的结点)
return 1;
}
(3)按位置插入
对单链表进行按位置插入,需要获取单链表的长度来判断插入位置是否有效
- 获取长度
int getLength(pList phead) { int count = 0; Node* pCur = phead; while (pCur != nullptr) { count++; pCur = pCur->next; } return count; }
int insertPos(pList phead, int pos, ElemType val) { Node* pnewnode = buyNode(val); int i = 0; Node* pfront = phead; //判断位置是否合理 if (pos < 0 || pos > getLength(phead)) { return 0;//失败,位置不合理非法 } for (i; i < pos; i++) { pfront = pfront->next;//找到插入点之前的结点 } pnewnode->next = pfront->next; pfront->next = pnewnode; return 1; }
4、删除
单链表删除结点时需先判空,若链表为空,则不用删除
-
判空
int empty(pList phead)
{
return phead->next == nullptr ? 1 : 0;
}
(1)头删
int deleteHead(pList phead)
{
/*
return deletePos(phead, 0);
*/
if (empty(phead))
{
return -1;
}
Node* pdel = phead->next;
phead->next = pdel->next;
free(pdel);
return 1;
}
(2)尾删
int deleteTail(pList phead)
{
Node* ptail2 = phead;
Node* pdel = nullptr;
if (empty(phead))
{
return -1;
}
while(ptail2->next != nullptr)//ptail2下一个结点存在
{
if (ptail2->next->next == nullptr)
{
break;
}
ptail2 = ptail2->next;//最后一个结点删除
}
pdel = ptail2->next;//pdel保存最后一个删除点
ptail2->next = nullptr;
free(pdel);
return 1;
}
(3)按位置删除
int deletePos(pList phead, int pos)
{
int i = 0;
Node* pfront = phead;
Node* pdel = nullptr;
if (pos < 0 || pos >= getLength(phead))
{
return -1;
}
for (i; i < pos; i++)
{
pfront = pfront->next;
}
pdel = pfront->next;
pfront->next = pdel->next;
free(pdel);
return 1;
}
5、打印
void Show(pList phead)
{
Node* pCur = phead->next;//第一个数据结点
while (pCur != nullptr)//数据结点存在
{
printf("%d ", pCur->data);
pCur = pCur->next;
}
printf("\n");
}
6、销毁
void destory(pList phead)
{
Node* pCur = phead->next;//第一个数据结点
Node* pNext = nullptr;
while (pCur != nullptr)//当前结点存在
{
pNext = pCur->next;
free(pCur);
pCur = pNext;
}
phead->next = nullptr;
}
主函数
#include <stdio.h>
#include "SeqList.h"
int main()
{
Node head;
int i = 0;
init(&head);
for (i; i < 5; i++)
{
insertHead(&head,i + 1);//5 4 3 2 1
}
Show(&head);
for (i=0; i < 5; i++)
{
insertTali(&head, i + 1);//5 4 3 2 1 1 2 3 4 5
}
Show(&head);
insertPos(&head, 6,100);
Show(&head);
deleteHead(&head); //4 3 2 1 1 100 2 3 4 5
Show(&head);
deleteTail(&head);//4 3 2 1 1 100 2 3 4
Show(&head);
deletePos(&head, 2);//4 3 1 1 100 2 3 4
Show(&head);
destory(&head);
return 0;
}