单链表:
结构体变量通过结构体指针连接在一起。
/*链表的结构体*/
#include <stdio.h>
typedef struct Node{
int data; //数据域,可以是任何类型的数据
struct Node* next; //指针域
}Node, *LinkedList;
其中,Node表示结点的类型,LinkedList表示指向Node结点类型的指针类型。
分类:
- 静态链表:链表分配在栈上;
- 动态链表:链表分配在堆上。
静态链表:
int main()
{
//结点创建
Node node1 = { 10,NULL };
Node node2 = { 20,NULL };
Node node3 = { 30,NULL };
//建立结点之间的关系
node1.next = &node2;
node2.next = &node3;
//遍历链表
struct Node* pCurrent = &node1;
while (pCurrent != NULL)
{
printf("%d\n", pCurrent->data);
pCurrent = pCurrent->next;
}
return 0;
}
动态链表:
int main()
{
# 结点创建
Node* node1 = (Node*)malloc(sizeof(Node));
Node* node2 = (Node*)malloc(sizeof(Node));
Node* node3 = (Node*)malloc(sizeof(Node));
# 给每个结点建立关系并给数据域赋值
node1->data = 10;
node1->next = node2;
node2->data = 20;
node2->next = node3;
node3->data = 30;
node3->next = NULL;
# 遍历链表
struct Node* pCurrent = node1;
while (pCurrent != NULL)
{
printf("%d\n", pCurrent->data);
pCurrent = pCurrent->next;
}
return 0;
}
单链表的基本使用:
(1)初始化链表:
具有返回值,该函数的返回值是: 创建好的链表的头结点。
# 初始化链表
# 函数的返回值是 创建好的链表的头结点
LinkedList init_LinkList()
{
# malloc()函数返回的为void*类型,需强转为Node*类型。
Node* pHeader = (Node*)malloc(sizeof(Node));
if (pHeader == NULL)
{
return NULL;
}
//pHeader->num = -1; //头结点初始化,一般不需要维护数据域
pHeader->next = NULL; //初始化一个空链表
# 创建一个结点指针,用于记录当前链表节点的位置,方便做尾插
Node* pCurrent = pHeader;
int val = -1;
while (1)
{
printf("请输入数据,-1代表结束\n");
scanf("%d", &val);
if (val == -1)
{
break;
}
# 创建新节点
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = val;
newNode->next = NULL;
# 更新节点指向
pHeader->next = newNode;
pCurrent = newNode;
}
return pHeader;
}
(2)遍历链表:
void print_List(LinkedList pHeader)
{
if (pHeader == NULL) //如果该节点为空,则不遍历
{
return;
}
//当前节点,指向第一个有真实数据的节点
Node* pCurrent = pHeader->next;
while(pCurrent != NULL)
{
printf("%d\n", pCurrent->data);
pCurrent = pCurrent->next;
}
printf("\n");
}
简单的遍历设计的函数只需要void无参即可,而当涉及到元素操作时,可以设计一个LinkedList类型的函数,使其返回一个操作后的新链表。
(3)链表结点的插入:
链表的插入操作主要分为:
- 查找到第i个位置;
- 将该位置的next指针修改为指向我们新插入的结点;
- 新插入的结点next指针指向i+1位置的结点。
利用两个辅助指针变量实现链表的插入:
① 在 oldval 前插入 newvalue,如果 oldval 不存在,则做尾插。
LinkedList insert_Linklist(LinkedList pHeader, int oldVal, int newVal)
{
if (pHeader == NULL)
{
return;
}
//创建两个临时指针事项节点插入
Node* pPre = pHeader;
Node* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
if (pCurrent->data == oldVal)
{
break;
}
//两个辅助指针向后移动
pPre = pCurrent;
pCurrent = pCurrent->next;
}
//创建新节点
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = newVal;
newNode->next = pCurrent;
pPre->next = newNode;
return pHeader;
}
② 在第 i 个位置插入值为 x 的结点。
LinkedList insert_Linklist(LinkedList pHeader, int i, int x)
{
if (pHeader == NULL)
{
return;
}
Node* pPre = pHeader;
for(int tmp=1; tmp<i;tmp++)
{
pPre = pPre->next; //查找第i个位置的前驱结点
}
//创建新节点
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = x;
newNode->next = pPre->next;
pPre->next = newNode;
return pHeader;
}
(4)删除节点
# 函数参数列表里的 struct Node* pHeader 也可以写成 LinkedList pHeader
LinkedList delete_LinkList(struct Node* pHeader, int delVal)
{
if (pHeader == NULL)
{
return;
}
Node* pPre = pHeader;
Node* pCurrent = pHeader->next;
while (pCurrent != NULL)
{
if (pCurrent->data == delVal)
{
break;
}
//移动两个辅助指针来遍历链表
pPre = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)
{
//没有找到用户需要删除的节点
return;
}
pPre->next = pCurrent->next;
free(pCurrent);
//pCurrent = NULL;
}
(5) 反转链表
void reverse_LinkList(LinkedList pHeader)
{
if (pHeader == NULL)
{
return;
}
LinkedList pPrev = NULL;
LinkedList pCurrent = pHeader->next;
LinkedList pNext = NULL;
while (pCurrent != NULL)
{
pNext = pCurrent->next;
pCurrent->next = pPrev;
pPrev = pCurrent;
pCurrent = pNext;
}
pHeader->next = pPrev;
}
(6)测试程序
int main(void)
{
Node* pHeader = init_LinkList();
printf("初始链表为:\n");
print_List(pHeader);
reverse_LinkList(pHeader);
printf("反转后链表为:\n");
print_List(pHeader);
return 0;
}