简介
本文主要介绍链表的头插、头删、尾插、尾删、查找、插入和删除,提供全部的.c和.h文件,确保使用者直接复制粘贴到编译器上即可直接运行程序。
动态顺序表结构体
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode * next;
} SLTNode;
1.头插功能
思路是将节点的首地址赋值到新申请节点的next中。
void SListPushFront ( SLTNode* * ppHead, SLTDateType x)
{
assert ( ppHead != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
newNode-> next = * ppHead;
* ppHead = newNode;
return ;
}
开辟一个新的节点,并将要插入的值放心节点对应的data中。
SLTNode* CreatListNode ( SLTDateType x)
{
SLTNode* newNode = ( SLTNode* ) malloc ( sizeof ( SLTNode) ) ;
if ( NULL == newNode)
{
printf ( "CreatListNode malloc fail\n" ) ;
exit ( - 1 ) ;
}
newNode-> data = x;
newNode-> next = NULL ;
return newNode;
}
2.头删功能
思路是将下一个节点的地址赋值到头节点地址上,将当前节点free掉。
void SListPopFront ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
SLTNode* next = ( * ppHead) -> next;
free ( * ppHead) ;
* ppHead = next;
return ;
}
3.尾插功能
思路是先检查输入*ppHead是否为空,不为空就找到链表的尾节点进行新节点的插入。
void SListPushBack ( SLTNode* * ppHead, SLTDateType x)
{
assert ( ppHead != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
if ( * ppHead == NULL )
{
* ppHead = newNode;
}
else
{
SLTNode* tail = * ppHead;
while ( tail-> next != NULL )
{
tail = tail-> next;
}
tail-> next = newNode;
}
return ;
}
4.尾删功能
思路是释放节点时,要将下一个节点的地址保存好再释放当前节点。
void SListPopBack ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
if ( ( * ppHead) -> next == NULL )
{
free ( * ppHead) ;
* ppHead = NULL ;
}
else
{
SLTNode* tail = * ppHead;
SLTNode* pre = NULL ;
while ( tail-> next != NULL )
{
pre = tail;
tail = tail-> next;
}
pre-> next = NULL ;
free ( tail) ;
tail = NULL ;
}
return ;
}
5.查找功能
思路是遍历,找到节点后返回当前节点的地址,找不到就返回NULL。
SLTNode* SListFind ( SLTNode* pHead, SLTDateType x)
{
assert ( pHead != NULL ) ;
SLTNode* cur = pHead;
while ( cur)
{
if ( cur-> data == x)
{
return cur;
}
else
{
cur = cur-> next;
}
}
return NULL ;
}
6.插入功能
6.1 指定位置之(前)去插入一个节点
此方法是比较笨的方法,为了节约资源应该将数据往指定位置的后边插入。
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x)
{
assert ( ppHead != NULL ) ;
assert ( pos != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
if ( * ppHead == pos)
{
newNode-> next = * ppHead;
* ppHead = newNode;
}
else
{
SLTNode* posPrev = * ppHead;
while ( posPrev-> next != pos)
{
posPrev = posPrev-> next;
}
posPrev-> next = newNode;
newNode-> next = pos;
}
return NULL ;
}
6.2 指定位置之(后)去插入一个节点
此方法是常用的插入方式,时间复杂度是O(1)。
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x)
{
assert ( pos != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
newNode-> next = pos-> next;
pos-> next = newNode;
return NULL ;
}
7.删除功能
7.1 删除指定位置的数据-时间复杂度O(N)
此方法需要记住当前节点前一个的节点地址,会多耗费时间资源,时间复杂度O(N)。
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos)
{
assert ( ppHead != NULL ) ;
assert ( pos != NULL ) ;
if ( * ppHead == pos)
{
SListPopFront ( ppHead) ;
}
else
{
SLTNode* prev = * ppHead;
while ( prev-> next != pos)
{
prev = prev-> next;
}
prev-> next = pos-> next;
free ( pos) ;
pos = NULL ;
}
return NULL ;
}
7.2 删除指定位置后一个位置的数据-时间复杂度O(1)
此方法需要记住当前节点前一个的节点地址,会多耗费时间资源,时间复杂度O(1)。
SLTNode* SListEraseAfter ( SLTNode* pos)
{
assert ( pos-> next != NULL ) ;
SLTNode* next = pos-> next;
pos-> next = next-> next;
free ( next) ;
next = NULL ;
return NULL ;
}
8. 将数字插入到有序链表中
思路是在有序的链表中,将数字插入到对应的位置上。
void SListInsertIndex ( SLTNode* * pHead, SLTDateType x)
{
assert ( pHead != NULL ) ;
SLTNode* cur = NULL ;
SLTNode* newNode = NULL ;
while ( ( cur = * pHead) != NULL && ( cur-> data < x) )
{
pHead = & cur-> next;
}
newNode = CreatListNode ( x) ;
newNode-> next = cur;
* pHead = newNode;
return ;
}
9. 释放链表缓存
思路将下一个节点的地址先记住,然后释放当前节点。再将保存的地址赋值到当前节点循环释放缓存。
SLTNode* SListDestory ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
SLTNode* cur = * ppHead;
while ( cur)
{
SLTNode* next = cur-> next;
free ( cur) ;
cur = next;
}
* ppHead = NULL ;
return NULL ;
}
10. 打印链表的值
void SListTPrint ( SLTNode* pHead)
{
SLTNode* cur = pHead;
while ( cur != NULL )
{
printf ( "%d->" , cur-> data) ;
cur = cur-> next;
}
return ;
}
11.此程序共包含3个文件,2个.c文件和1个.h文件
11.1 SList.h文件
文件中包含了函数功能的头文件以及对应的结构体。
# pragma once
# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode * next;
} SLTNode;
void SListTPrint ( SLTNode * pHead) ;
void SListPushBack ( SLTNode* * ppHead, SLTDateType x) ;
void SListPushFront ( SLTNode* * ppHead, SLTDateType x) ;
void SListPopBack ( SLTNode* * ppHead) ;
void SListPopFront ( SLTNode* * ppHead) ;
SLTNode* SListFind ( SLTNode* pHead, SLTDateType x) ;
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x) ;
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x) ;
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos) ;
SLTNode* SListEraseAfter ( SLTNode* pos) ;
SLTNode* SListDestory ( SLTNode* * ppHead) ;
SLTNode* CreatListNode ( SLTDateType x) ;
11.2 SList.c文件
文件中包含了功能函数的具体实现方式。
# define _CRT_SECURE_NO_WARNINGS
# include "SList.h"
void SListPushBack ( SLTNode* * ppHead, SLTDateType x)
{
assert ( ppHead != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
if ( * ppHead == NULL )
{
* ppHead = newNode;
}
else
{
SLTNode* tail = * ppHead;
while ( tail-> next != NULL )
{
tail = tail-> next;
}
tail-> next = newNode;
}
return ;
}
void SListPushFront ( SLTNode* * ppHead, SLTDateType x)
{
assert ( ppHead != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
newNode-> next = * ppHead;
* ppHead = newNode;
return ;
}
SLTNode* CreatListNode ( SLTDateType x)
{
SLTNode* newNode = ( SLTNode* ) malloc ( sizeof ( SLTNode) ) ;
if ( NULL == newNode)
{
printf ( "CreatListNode malloc fail\n" ) ;
exit ( - 1 ) ;
}
newNode-> data = x;
newNode-> next = NULL ;
return newNode;
}
void SListPopBack ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
if ( ( * ppHead) -> next == NULL )
{
free ( * ppHead) ;
* ppHead = NULL ;
}
else
{
SLTNode* tail = * ppHead;
SLTNode* pre = NULL ;
while ( tail-> next != NULL )
{
pre = tail;
tail = tail-> next;
}
pre-> next = NULL ;
free ( tail) ;
tail = NULL ;
}
return ;
}
void SListPopFront ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
SLTNode* next = ( * ppHead) -> next;
free ( * ppHead) ;
* ppHead = next;
return ;
}
SLTNode* SListFind ( SLTNode* pHead, SLTDateType x)
{
assert ( pHead != NULL ) ;
SLTNode* cur = pHead;
while ( cur)
{
if ( cur-> data == x)
{
return cur;
}
else
{
cur = cur-> next;
}
}
return NULL ;
}
SLTNode* SListInsert ( SLTNode* * ppHead, SLTNode* pos, SLTDateType x)
{
assert ( ppHead != NULL ) ;
assert ( pos != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
if ( * ppHead == pos)
{
newNode-> next = * ppHead;
* ppHead = newNode;
}
else
{
SLTNode* posPrev = * ppHead;
while ( posPrev-> next != pos)
{
posPrev = posPrev-> next;
}
posPrev-> next = newNode;
newNode-> next = pos;
}
return NULL ;
}
SLTNode* SListInsertAfter ( SLTNode* pos, SLTDateType x)
{
assert ( pos != NULL ) ;
SLTNode* newNode = CreatListNode ( x) ;
newNode-> next = pos-> next;
pos-> next = newNode;
return NULL ;
}
SLTNode* SListErase ( SLTNode* * ppHead, SLTNode* pos)
{
assert ( ppHead != NULL ) ;
assert ( pos != NULL ) ;
if ( * ppHead == pos)
{
SListPopFront ( ppHead) ;
}
else
{
SLTNode* prev = * ppHead;
while ( prev-> next != pos)
{
prev = prev-> next;
}
prev-> next = pos-> next;
free ( pos) ;
pos = NULL ;
}
return NULL ;
}
SLTNode* SListEraseAfter ( SLTNode* pos)
{
assert ( pos-> next != NULL ) ;
SLTNode* next = pos-> next;
pos-> next = next-> next;
free ( next) ;
next = NULL ;
return NULL ;
}
SLTNode* SListDestory ( SLTNode* * ppHead)
{
assert ( ppHead != NULL ) ;
SLTNode* cur = * ppHead;
while ( cur)
{
SLTNode* next = cur-> next;
free ( cur) ;
cur = next;
}
* ppHead = NULL ;
return NULL ;
}
void SListTPrint ( SLTNode* pHead)
{
SLTNode* cur = pHead;
while ( cur != NULL )
{
printf ( "%d->" , cur-> data) ;
cur = cur-> next;
}
return ;
}
11.3 test.c文件
用来进行相应功能的测试,分别测试尾插、尾删和头插、头删等功能。
# define _CRT_SECURE_NO_WARNINGS
# include <stdio.h>
# include "SList.h"
void Test1 ( )
{
SLTNode* SList = NULL ;
SListPushBack ( & SList, 1 ) ;
SListPushBack ( & SList, 2 ) ;
SListPushBack ( & SList, 3 ) ;
SListPushBack ( & SList, 4 ) ;
SListPopBack ( & SList) ;
SListTPrint ( SList) ;
printf ( "NULL\n" ) ;
return ;
}
void Test2 ( )
{
SLTNode* SList = NULL ;
SListPushFront ( & SList, 1 ) ;
SListPushFront ( & SList, 2 ) ;
SListPushFront ( & SList, 3 ) ;
SListPopFront ( & SList) ;
SListTPrint ( SList) ;
printf ( "NULL" ) ;
return ;
}
void Test3 ( )
{
SLTNode* SList = NULL ;
SLTNode* pos = NULL ;
int i = 1 ;
SListPushBack ( & SList, 1 ) ;
SListPushBack ( & SList, 5 ) ;
SListPushBack ( & SList, 2 ) ;
SListPushBack ( & SList, 3 ) ;
SListPushBack ( & SList, 2 ) ;
pos = SListFind ( SList, 2 ) ;
while ( pos)
{
printf ( "第%d个pos节点的:%p->%d\n" , i++ , pos-> next, pos-> data) ;
if ( pos-> next)
{
pos = SListFind ( pos-> next, 2 ) ;
}
else
{
break ;
}
}
pos = SListFind ( SList, 5 ) ;
if ( pos)
{
SListInsert ( & SList, pos, 20 ) ;
}
pos = SListFind ( SList, 5 ) ;
if ( pos)
{
SListInsertAfter ( pos, 100 ) ;
}
SListTPrint ( SList) ;
printf ( "NULL" ) ;
return ;
}
void Test ( )
{
int i = 0 ;
SLTNode* SList = NULL ;
for ( i = 0 ; i < 5 ; i++ )
{
SListPushBack ( & SList, 2 * i + 1 ) ;
}
SListTPrint ( SList) ;
printf ( "NULL\n" ) ;
SListInsertIndex ( & SList, 10 ) ;
SListTPrint ( SList) ;
printf ( "NULL\n" ) ;
return ;
}
int main ( )
{
Test ( ) ;
return 0 ;
}
这里代码大家可以自己拷贝到VS编译器中,Test1(),Test2(),Test3(),Test()分别打开注释看一下效果,本人亲测过,可以直接运行出结果的。