链表是一种链式存储线性表,用一组地址任意的存储单元存放数据表的数据元素,称为存储单元的一个节点
节点的结构体定义为:
typedef struct ListNode
{
struct ListNode* pNext;
TypeDate data;
}ListNode;
下面就是一些构造链表的一些 函数,包括删除,插入,销毁等:
创建一个节点
ListNode* BuyNode(TypeDate x)
{
ListNode* Node = (ListNode*)malloc(sizeof(ListNode));
Node->pNext = NULL;
Node->data = x;
assert(Node);
return Node;
}
头插:就是从头节点处 插入一个节点:
void SListPushfront(ListNode** ppHead, TypeDate x)//头插
{
ListNode* NewNode=NULL;
NewNode = BuyNode(x);
if (*ppHead == NULL)
{
*ppHead = NewNode;
NewNode->pNext = NULL;
}
else
{
NewNode->pNext=*ppHead;
*ppHead=NewNode;
}
}
尾插 :
对于单向有头不循环链表而言:需要找到链表中的最后一个节点,再将需要插入的节点插入:
void SListPushback(ListNode** ppHead, TypeDate x)//尾插
{
ListNode* NewNode = NULL;
ListNode* cur = NULL;
NewNode = BuyNode(x);
if (*ppHead == NULL)
{
*ppHead = NewNode;
NewNode->pNext = NULL;
}
else
{
cur = *ppHead;
while (cur)
{
if (cur->pNext == NULL)
{
cur->pNext = NewNode;
NewNode->pNext = NULL;
}
cur = cur->pNext;
}
}
}
头删:
将第一个节点删除,定义一个节点保存头节点,再将头节点的下一个节点赋为头节点,最后释放头节点。
void SListPopfront(ListNode** ppHead)//头删
{
ListNode* Node=NULL;
if (*ppHead == NULL)
{
return;
}
else
{
Node = *ppHead;
*ppHead=(*ppHead)->pNext;
free(Node);
}
}
尾删:
找到倒数第二个节点,将倒数第二个节点的下一个指向NULL
void SListPopback(ListNode** ppHead)//尾删
{
ListNode* cur = NULL;
if (*ppHead == NULL)
{
return;
}
else
{
cur = *ppHead;
while (cur)
{
if ((cur->pNext)->pNext == NULL)
{
cur->pNext = NULL;
free(cur->pNext);
}
cur = cur->pNext;
}
}
}
删除任意一个节点:
void SListErase(ListNode** ppHead, ListNode* PposNode)//在任意位置删除
{
ListNode* PNode = NULL;
PNode = *ppHead;
if (*ppHead == NULL)
{
return 0;
}
else
{
while (PNode->pNext != PposNode)//找到需要删除的位置的前一个
{
PNode = PNode->pNext;
}
PNode->pNext = PposNode->pNext;
free(PposNode);
}
}
在任意位置插入一个节点:
void SListInsert(ListNode** ppHead, ListNode* PposNode, TypeDate x)//在任意位置插入
{
ListNode* PNode = NULL;
ListNode* NewNode = NULL;
PNode = *ppHead;
NewNode = BuyNode(x);
if (*ppHead == NULL)
{
*ppHead = NewNode;
}
if (*ppHead == PposNode)
{
SListPushfront(ppHead, x);
}
else
{
while (PNode->pNext != PposNode)
{
PNode = PNode->pNext;
}
NewNode->pNext = PposNode;
PNode->pNext = NewNode;
}
}
按值删除(删除遇到的第一个 ):
如果链表为空,则返回空,若不是空链表,则遍历整个链表 ,比较节点的值是否与所需要删除的节点的值是一样的,如果是一样的就删除这个节点,然后退出。如果没有与其匹配的,就返回空。
void SListRemove(ListNode** ppHead, TypeDate x)//按值删除,删除遇到的第一个
{
ListNode* PNode = NULL;
ListNode* cur = NULL;
PNode = *ppHead;
if (*ppHead == NULL)
{
return;
}
else
{
while ((PNode->pNext)->data != x)
{
PNode = PNode->pNext;
}
cur = PNode->pNext;
PNode->pNext = cur->pNext;
free(cur);
}
}
按值删除(删除链表中为这个值得所有节点):
思想:遍历整个链表,当找到数据相同的节点,删除这个节点后,并不退出,要将当前节点赋给下一个节点,仔计算查找。
核心:要将当前节点用一个临时节点代替,否则,找到了需要删除了的节点后,会将这个节点释放那么再使用这个节点将会产生错误。
void SListRemoveAll(ListNode** ppHead, TypeDate x)//按值删除,删除所有的
{
ListNode* PNode = NULL;
ListNode* cur = NULL;
PNode = *ppHead;
if (*ppHead == NULL)
{
return;
}
else
{
while (PNode->pNext)
{
if ((PNode->pNext)->data == x)
{
cur = PNode->pNext;
PNode->pNext = cur->pNext;
free(cur);
}
else
{
PNode = PNode->pNext;
}
}
}
}
销毁链表:
思想:遍历整个链表,将链表的,从头节点开始释放,直至链表为空。
void SListDestory(ListNode** ppHead)
{
ListNode* PNode = NULL;
ListNode* Pnext = NULL;
for (PNode = *ppHead; PNode != NULL; PNode = Pnext)
{
Pnext = PNode->pNext;
free(PNode);
}
ppHead=NULL;
}
测试代码:
void test()
{
ListNode* S=NULL;//初始化链表
printf("前插后:\n");
SListPushfront(&S, 2);
SListPushfront(&S, 4);
SListPushfront(&S, 6);
SListPushfront(&S, 6);
SListPushfront(&S, 6);
SListPushfront(&S, 8);
SListPushfront(&S, 2);
SListPushback(&S, 12);
SListPrint(S);
printf("后插后:\n");
SListPushback(&S, 10);
SListPushback(&S, 11);
SListPushback(&S, 12);
SListPushback(&S, 14);
SListPushback(&S, 14);
SListPushback(&S, 16);
SListPrint(S);
printf("前删和后删:\n");
SListPopfront(&S);
SListPopfront(&S);
SListPopback(&S);
SListPopback(&S);
SListPrint(S);
printf("插入到指定位置:\n");
SListInsert(&S, &S->pNext->pNext, 17);
SListInsert(&S, &S->pNext, 0);
SListPrint(S);
printf("删除指定位置:\n");
SListErase(&S, &S->pNext->pNext);
SListPrint(S);
printf("按值删除,只删遇到的第一个:\n");
SListRemove(&S, 12);
SListPrint(S);
printf("按值删除,只删所有:\n");
SListRemoveAll(&S, 6);
SListPrint(S);
/*printf("销毁链表!");
SListDestory(&S);
SListPrint(S);*/
}
程序的结果是: