简介
特点:节点由数据和指向下一个节点的指针组成,内存不连续。
时间复杂度:访问元素为O(n),插入/删除元素为O(1)(只需更改指针)。
应用场景:频繁插入和删除操作,数据动态变化。
实现单链表
创建SList.h, SList.c, test.c三个文件
初始化单链表
数据data+指向下一结点指针*next
//定义链表(结点)的结构
typedef int SLTDataType;
typedef struct SListNode {
SLTDataType data;
struct SListNode* next;
}SLTNode;
新增结点
//申请新结点
SLTNode* SLTBuyNode(SLTDataType x)
{
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
if (node == NULL)
{
perror("malloc fail!");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
创建单链表
1.申请空间
2.node->data=x;
3.node->next=node(+1)
#include"SList.h"
//创建一个链表,并打印链表
void createSList()
{
//链表是由一个一个的结点组成
SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
node1->data = 1;
SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
node2->data = 2;
SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
node3->data = 3;
SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
node4->data = 4;
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = NULL;
//第一个结点的地址作为参数传递过去
SLTNode* plist = node1;
SLTPrint(plist);
}
void SListTest01()
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist);//1->2->3->4->NULL
//SLTPushBack(NULL, 3);
//SLTPushFront(&plist, 1);
//SLTPushFront(&plist, 2);
//SLTPushFront(&plist, 3);
//SLTPushFront(&plist, 4);
//SLTPrint(plist); //4->3->2->1->NULL
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTNode* find = SLTFind(plist, 4);
//if (find == NULL)
//{
// printf("未找到!\n");
//}
//else
//{
// printf("找到了!\n");
//}
//SLTInsert(&plist, find, 11);//4->3->2->11->1->NULL
//SLTInsertAfter(find, 11);
//SLTPrint(plist);1->11->2->3->4->NULL
//SLTErase(&plist, find);// 1->2->3->NULL
//SLTEraseAfter(find);
//SLTPrint(plist);
SListDestroy(&plist);
SLTPrint(plist);
}
struct ListNode {
int val;
struct ListNode *next;
};
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
//创建新链表
ListNode* newHead, * newTail;
newHead = newTail = NULL;
//遍历原链表
ListNode* pcur = head;
while (pcur)
{
//找值不为val的节点,往新链表中进行尾插
if (pcur->val != val)
{
//链表为空
if (newHead == NULL)
{
newHead = newTail = pcur;
}
else
{
//链表不为空
newTail->next = pcur;
newTail = newTail->next;
}
}
pcur = pcur->next;
}
return newHead;
}
void test01()
{
ListNode* n1 = (ListNode*)malloc(sizeof(ListNode));
n1->val = 1;
ListNode* n2 = (ListNode*)malloc(sizeof(ListNode));
n2->val = 6;
ListNode* n3 = (ListNode*)malloc(sizeof(ListNode));
n3->val = 1;
ListNode* n4 = (ListNode*)malloc(sizeof(ListNode));
n4->val = 6;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
//1->6->1->6
ListNode* plist = n1;
//构造一个链表
removeElements(plist, 6);
//1->1
}
int main()
{
//createSList();
//SListTest01();
test01();
return 0;
}
打印单链表
用指针从头到尾遍历打印,pcur->next=NULL时停止
//打印单链表
void SLTPrint(SLTNode* phead)
{
SLTNode* pcur = phead;
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("NULL\n");
}
插入
尾插
创建pcur指针从头遍历单链表到尾,若pcur->next=NULL,则为尾结点,然后插入,pcur -> next=newnode
void SLTPushBack(SLTNode* phead, SLTDataType x);//尾插
//尾插
void SLTPushBack(SLTNode* phead, SLTDataType x)
{
//申请新节点
SLTNode* newnode = SLTBuyNode(x);
if (phead == NULL)
{
phead = newnode;
}
else
{
//找尾结点
SLTNode* pcur = phead;
while (pcur->next)
{
pcur = pcur->next;
}
//pcur newnode
pcur->next = newnode;
}
}
头插
回顾 指针
- 一级指针:用于访问或修改指针指向的变量的值。
-
void modifyValue(int *p) { *p = 20; // 改变一级指针p指向的变量的值 } int main() { int a = 10; modifyValue(&a); // 传递变量a的地址 printf("%d", a); // 输出20,表示a的值被修改 return 0; }
- 二级指针:用于修改一级指针的指向,让它指向不同的内存位置。
-
void modifyPointer(int **pp) { static int b = 30; *pp = &b; // 改变一级指针pp指向b的地址 } int main() { int a = 10; int *p = &a; // p指向a modifyPointer(&p); // 传递p的地址 printf("%d", *p); // 输出30,表示p现在指向了b return 0; }
一级指针指向某个变量的内存地址,允许通过指针访问或修改这个变量的值。
二级指针是指向一级指针的指针。通过二级指针,你可以修改一级指针本身的值,也就是让一级指针指向不同的内存地址。
想要改变头结点指针的指向,传二级指针,一级指针改变数据的值,二级指针改变一级指针的指向
void SLTPushFront(SLTNode** pphead, SLTDataType x);
*pphead前插入newnode
*pphead指向newnode
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = SLTBuyNode(x);
//newnode *pphead
newnode->next = *pphead;
*pphead = newnode;
}
在指定位置之前插⼊数据
在头前插入,会改变头指针,传二级指针
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
设置prev指针从头遍历,在pos之前插入
也就是说newnode->next=pos , prev->next=newnode
newnode
prev------------------------->pos prev---------------->newnode------------------>pos
prev->next prev->next new->next
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
else
{
SLTNode* newnode = SLTBuyNode(x);
//找prev :pos的前一个结点
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//prev newnode --> pos
newnode->next = pos;
prev->next = newnode;
}
}
在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = SLTBuyNode(x);
//pos newnode --> pos->next
newnode->next = pos->next;
pos->next = newnode;
}
删除
尾删
void SLTPopBack(SLTNode** pphead);
//尾删
void SLTPopBack(SLTNode** pphead)
{
//链表为空:不可以删除
assert(pphead && *pphead);
//处理只有一个结点的情况:要删除的就是头结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
//找 prev ptail
SLTNode* ptail = *pphead;
SLTNode* prev = NULL;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
prev->next = NULL;
free(ptail);
ptail = NULL;
}
头删
void SLTPopFront(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* next = (*pphead)->next;
//*pphead --> next
free(*pphead);
*pphead = next;
}
删除指定的pos结点
void SLTErase(SLTNode * *pphead, SLTNode * pos);
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead && *pphead);
assert(pos);
//头删
if (pos == *pphead)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//prev pos pos->next
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
删除pos之后的结点
void SLTEraseAfter(SLTNode * pos);
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos && pos->next);
//pos pos->next pos->next->next
SLTNode* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
assert(phead);
SLTNode* pcur = phead;
while (pcur)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//没有找到
return NULL;
}
销毁单链表
//销毁链表
void SListDestroy(SLTNode * *pphead);
//销毁链表
void SListDestroy(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}