数据结构复习之单链表的基本操作--C语言实现
#include<stdio.h>
#include<stdlib.h>
/*
* 默认带头结点
* 1.单链表定义
* 2.头插法
* 3.尾插法
* 4.在指定位置插入一个结点 tips:可以封装在p结点之后插入一个结点
* 5.在某结点之前插入一个结点 ---> O(n)和O(1)实现方式
* 6.在某结点之后插入一个结点
* 7.删除指定结点 ---> O(n)和O(1)实现方式
*/
typedef int ElemType;
//1.单链表定义
typedef struct LNode
{
ElemType data;
struct LNode* next;
}LNode, *LinkList;
//初始化
void InitLinkList(LinkList *L)
{
*L = (LinkList)malloc(sizeof(LNode));
(*L)->next = NULL;
}
//2.头插法
LinkList List_HeadInsert(LinkList L,LNode *node)
{
//1.若待插入结点是null,则不插入,直接返回L
if (node == NULL)
{
return L;
}
node->next = L->next;
L->next = node;
return L;
}
//3.尾插法
LinkList List_TailInsert(LinkList L, LNode* node)
{
//1.若待插入结点是null,则不插入,直接返回L
if (node == NULL)
{
return L;
}
LNode* p = L;
//2.寻找单链表尾部
while (p->next != NULL)
{
p = p->next;
}
//3.讲新结点加入到链表尾部
p->next = node;
return L;
}
void PrintLinkList(LinkList L)
{
LNode* p = L->next;
while (p != NULL)
{
printf("%d,",p->data);
p = p->next;
}
printf("\n");
}
//返回第i个结点
LNode* getNode(LinkList L, int index)
{
if (index < 0)
{
return NULL;
}
else
{
int j = 0; //指示当前第几个结点
LNode* p = L;
//寻找第index结点
while (p != NULL && j < index)
{
p = p->next;
++j;
}
return p;
}
}
//4.在指定位置插入一个结点
bool ListInsert(LinkList L, int index, ElemType e)
{
if (index < 1)
{
return false;
}
LNode* p = NULL;
//先寻找第index-1结点
p = getNode(L, index - 1);
//若p是null,说明index大于length+1,也就是说传入了不合法的位序index,直接return false
if (p == NULL)
{
return false;
}
//找到第index-1结点后,将新结点结点追加到它后面
LNode* q = (LNode*)malloc(sizeof(LNode));
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
//5.在某结点之前插入一个结点
//5.1知道单链表头结点,在node前插入一个新结点。时间复杂度是O(n)
bool ListInsertBefore(LinkList L, int index, ElemType e)
{
if (index < 1)
{
return false;
}
//先获取第index-1结点
LNode* p = getNode(L,index-1);
if (p == NULL)
{
return false;
}
LNode* q = (LNode*)malloc(sizeof(LNode));
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
//5.2不知道单链表头结点,希望在node前插入一个新结点q
//可以先将新结点插入到node后面,然后交换node和q的data即可(在node前插入的逻辑上是对的),时间复杂度是O(1)
bool ListInsertBefore2(LNode* node, ElemType e)
{
if (node == NULL)
{
return false;
}
//将新结点q插入到node的后面
LNode* q = (LNode*)malloc(sizeof(LNode));
q->next = node->next;
node->next = q;
//然后交换node和新结点q的data
q->data = node->data;;
node->data = e;
return true;
}
//6.在某结点后面插入一个结点
bool ListInsertAfter(LinkList L, LNode* node, ElemType e)
{
if (node == NULL)
{
return false;
}
LNode* q = (LNode*)malloc(sizeof(LNode));
q->data = e;
q->next = node->next;
node->next = q;
return true;
}
//7.删除结点
//7.1删除第index结点,时间复杂度是O(n)
bool ListDelete(LinkList L, int index, ElemType* e)
{
if (index < 1)
{
return false;
}
LNode* p = getNode(L, index - 1);
if(p == NULL)
{
return false;
}
LNode* node = p->next; //node是被删除的结点
p->next = node->next; //node的前驱指向node的后继
free(node); //释放node
return true;
}
//7.2删除node,可以先将node的data修改为node1后继的data再删除node的后继,逻辑上也实现了删除node
//但是当删除单链表尾部元素时,将出错。因为尾部已经是最后一个元素,不存在后继,或者说它的后继是NULL
//时间复杂度是O(1)
bool ListDelete2(LNode *node, ElemType* e)
{
if (node == NULL)
{
return false;
}
LNode* p = node ->next;
if (p == NULL)
{
return false;
}
node->data = p->data; //将node的data修改为node后继的data
node->next = p->next; //node指向node后继的后继
free(p); //释放node的后继
return true;
}
本文介绍了使用C语言实现单链表的基本操作,包括初始化、头插法、尾插法、在指定位置插入和删除结点等,并探讨了不同操作的时间复杂度,如O(1)和O(n)的实现方式。

3651

被折叠的 条评论
为什么被折叠?



