文章目录 简介 动态顺序表结构体 1.头插功能 2.头删功能 3.尾插功能 4.尾删功能 5.查找功能 6.插入功能 6.1 指定位置之(前)去插入一个节点 6.2 指定位置之(后)去插入一个节点 7.删除功能 7.1 删除指定位置的数据-时间复杂度O(N) 7.2 删除指定位置后一个位置的数据-时间复杂度O(1) 8. 释放链表缓存 9. 打印链表的值 10.此程序共包含3个文件,2个.c文件和1个.h文件 10.1 SList.h文件 10.2 SList.c文件 10.3 test.c文件
简介
本文主要介绍链表的头插、头删、尾插、尾删、查找、插入和删除,提供全部的.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. 释放链表缓存
思路将下一个节点的地址先记住,然后释放当前节点。再将保存的地址赋值到当前节点循环释放缓存。
SLTNode* SListDestory ( SLTNode* * ppHead)
{ assert ( ppHead != NULL ) ; SLTNode* cur = * ppHead; while ( cur) { SLTNode* next = cur-> next; free ( cur) ; cur = next; } * ppHead = NULL ; return NULL ;
}
9. 打印链表的值
void SListTPrint ( SLTNode* pHead)
{ SLTNode* cur = pHead; while ( cur != NULL ) { printf ( "%d->" , cur-> data) ; cur = cur-> next; } return ;
}
10.此程序共包含3个文件,2个.c文件和1个.h文件
10.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) ;
10.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 ;
}
10.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 ;
} int main ( )
{ Test1 ( ) ; return 0 ;
}
这里代码大家可以自己拷贝到VS编译器中,Test1(),Test2(),Test3(),分别打开注释看一下效果,本人亲测过,可以直接运行出结果的。