概述
单向链表特点
- 只能顺序查找,时间复杂度O(n)
- 增加和删除操作开销小,适用于频繁增删的场景
设计数据结构
链表节点
typedef struct Node {
int _data;
struct Node *_pNext;
}Node_t, *pNode_t;
链表
typedef struct List {
pNode_t _pHead; //头指针
pNode_t _pTail; //尾指针
int _size; //链表大小
}List_t, *pList_t;
单向链表的相关操作
- 初始化
- 判空
- 销毁(销毁堆空间)
- 插入(头插、尾插、有序插入)
- 删除(按值删除、按位删除)
- 查找(按值查找、按位查找)
- 修改(按值修改、按位修改)
操作实现思路
初始化(参数:链表地址)
- 头尾指针置为空
判空(参数:链表地址)
- 头指针 == NULL
销毁(参数:链表地址)
- 非空时,遍历链表,挨个free节点
头插(参数:链表地址,插入值)
- 新建结点,初始化
- 链表为空时,头尾指针指向新节点
- 链表非空时,新节点指向头指针,重置头指针
- ++size
尾插(参数:链表地址,插入值)
- 新建结点,并初始化
- 链表为空时,头尾指针指向新节点
- 链表非空时,尾指针指向,重置尾指针
- ++size
有序插入(参数:链表地址,插入值)
- 新建结点,并初始化
- 链表为空时,头尾指针指向新节点
- 链表非空时,且新节点最小,头插
- 链表非空时,找第一个大于新节点的地址
- pPre指针(用来放新节点),pCur指针(用来找位置)
- 遍历链表,
for (pPre = pList->_pHead, pCur = pPre->_pNext; pCur; pPre = pCur, pCur = pCur->_pNext)
- 找到第一个大于插入值的位置,将新节点连接pPre和pCur,break
- 如果
NULL == pCur
,表示没找到比新节点大的位置,尾插
- ++size
按值删除(参数:链表地址,待删除值)
- 如果链表为空,报错返回
- 如果链表非空,pCur遍历链表,找每一个待删除值的位置,pDel指向带删除值
- 保存待删除结点地址
- 如果是头节点,修改链表头指针
- 如果是尾结点,修改链表尾指针
- 修改相关指针,free待删除结点
- –size
按位删除(参数:链表地址,删除位置)
- 如果位置非法,报错返回
- 如果链表为空,报错返回
- 如果链表非空,遍历链表,找到位置,pDel指向带删除值
- 保存待删除结点地址
- 如果是第一个元素,修改表头指针
- 如果是最后一个元素,修改表尾指针
- 修改相关指针,free待删除结点
- –size
按值查找(参数:链表地址,待查询值)
- 如果链表为空,报错返回
- 遍历链表,找到返回地址,没找到返回NULL
按位查找(参数:链表地址,待查询位置)
- 如果链表为空,报错返回
- 如果位置非法,报错返回
- 遍历链表,找到返回地址,没找到返回NULL
按值修改(参数:链表地址,待修改值)
- 如果链表为空,报错返回
- 遍历链表,找到就修改,没找到返回NULL
按位修改(参数:链表地址,待修改位置)
- 如果链表为空,报错返回
- 如果位置非法,报错返回
- 遍历链表,找到就修改,没找到返回NULL
代码
头文件 list.h
#ifndef __LIST_H__
#define __LIST_H__
//将数据类型提取出来,方便修改
#define TYPENAME int
//链表结点
typedef struct Node {
TYPENAME _data;
struct Node *_pNext;
}Node_t, *pNode_t;
//链表
typedef struct List {
pNode_t _pHead;
pNode_t _pTail;
int _size;
}List_t, *pList_t;
//初始化
void list_init(pList_t pL);
int list_init_arr(pList_t pL, TYPENAME *begin, TYPENAME *end);
//判空
int list_empty(pList_t pL);
//销毁
void list_destroy(pList_t pL);
//插入
void list_headInsert(pList_t pL, TYPENAME val);
void list_tailInsert(pList_t pL, TYPENAME val);
void list_sortInsert(pList_t pL, TYPENAME val);
//删除
int list_erase_val(pList_t pL, TYPENAME val);
int list_erase_pos(pList_t pL, int pos);
//查找
pNode_t list_find_val(pList_t pL, TYPENAME val);
pNode_t list_find_pos(pList_t pL, int pos);
//修改
int list_modify_val(pList_t pL, TYPENAME oldval, TYPENAME newval);
int list_modify_pos(pList_t pL, int pos, TYPENAME newval);
//展示链表
void list_show(pList_t pL);
//得到链表长度
int list_size(pList_t pL);
#endif
实现文件 list.c
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//初始化
void list_init(pList_t pL)
{
pL->_pHead = pL->_pTail = NULL;
pL->_size = 0;
}
int list_init_arr(pList_t pL, TYPENAME *begin, TYPENAME *end)
{
if (!begin || !end || begin > end) {
return -1;
}
list_init(pL);
TYPENAME *start = begin;
for (; start <= end; ++start) {
list_sortInsert(pL, *start);
}
return 0;
}
//判空
int list_empty(pList_t pL)
{
return 0 == pL->_size;
/* return NULL == pL->_pHead; */
}
//销毁
void list_destroy(pList_t pL)
{
if (list_empty(pL)) {
return;
}
//释放每一个结点
int len = pL->_size;
for (int i = 0; i < len; ++i) {
list_erase_pos(pL, 1);
}
return;
}
//插入
void list_headInsert(pList_t pL, TYPENAME val)
{
pNode_t pNew = (pNode_t)calloc(1, sizeof(Node_t));
pNew->_data = val;
if (list_empty(pL)) {
pL->_pHead = pL->_pTail = pNew;
pL->_size++;
return;
}
//插在头部,修改头指针
pNew->_pNext = pL->_pHead;
pL->_pHead = pNew;
pL->_size++;
return;
}
void list_tailInsert(pList_t pL, TYPENAME val)
{
pNode_t pNew = (pNode_t)calloc(1, sizeof(Node_t));
pNew->_data = val;
if (list_empty(pL)) {
pL->_pHead = pL->_pTail = pNew;
pL->_size++;
return;
}
//插在尾部,修改尾指针
pL->_pTail->_pNext = pNew;
pL->_pTail = pNew;
pL->_size++;
return;
}
void list_sortInsert(pList_t pL, TYPENAME val)
{
pNode_t pNew = (pNode_t)calloc(1, sizeof(Node_t));
pNew->_data = val;
if (list_empty(pL)) {
pL->_pHead = pL->_pTail = pNew;
pL->_size++;
return;
}
//插入值最小,头插,修改头指针
if (val < pL->_pHead->_data) {
pNew->_pNext = pL->_pHead;
pL->_pHead = pNew;
pL->_size++;
return;
}
//插入值不是最小的,找第一个比它大的元素,插在其前面
pNode_t pPre = pL->_pHead;
pNode_t pCur = pPre->_pNext;
for (; pCur; pPre = pCur, pCur = pCur->_pNext) {
if (val < pCur->_data) {
pPre->_pNext = pNew;
pNew->_pNext = pCur;
break;
}
}
//没找到比插入值大的, 尾插
if (NULL == pCur) {
pL->_pTail->_pNext = pNew;
pL->_pTail = pNew;
}
pL->_size++;
return;
}
//删除
int list_erase_val(pList_t pL, TYPENAME val)
{
if (list_empty(pL)) {
fprintf(stderr, "List is empty, cannot erase!\n");
return -1;
}
pNode_t pCur = NULL;
if (val == pL->_pHead->_data) {
//删除值是第一个,修改头指针
pCur = pL->_pHead;
pL->_pHead = pL->_pHead->_pNext;
if (1 == pL->_size) {
pL->_pTail = NULL;
}
}
else {
//删除值不在首位, 遍历链表查找是否存在
pNode_t pPre = pL->_pHead;
pCur = pPre->_pNext;
for (; pCur; pPre = pCur, pCur = pCur->_pNext) {
if (val == pCur->_data) {
pPre->_pNext = pCur->_pNext;
break;
}
}
//删除值是最后一个,修改尾指针
if (pCur == pL->_pTail) {
pL->_pTail = pPre;
}
}
if (NULL != pCur) {
//删除值存在
free(pCur);
pCur = NULL;
--pL->_size;
return 0;
}
else {
fprintf(stderr, "Not found delete!\n");
return -1;
}
}
int list_erase_pos(pList_t pL, int pos)
{
if (list_empty(pL)) {
fprintf(stderr, "List is empty, cannot delete!\n");
return -1;
}
if (pos < 0 || pos > pL->_size) {
fprintf(stderr, "Delete_pos is illegal!\n");
return -1;
}
//位置合法,找到删除
pNode_t pCur = pL->_pHead;
if (1 == pos) {
//是第一个
pL->_pHead = pCur->_pNext;
if (pCur == pL->_pTail) {
//链表只有一个元素
pL->_pTail = pL->_pHead;
}
}
else {
//不是第一个,遍历链表查找
pNode_t pPre = pCur;
pCur = pCur->_pNext;
int i = 2;
for (; pCur; pPre = pCur, pCur = pCur->_pNext) {
if (i == pos) {
pPre->_pNext = pCur->_pNext;
break;
}
++i;
}
//删除的是尾节点
if (pCur == pL->_pTail) {
pL->_pTail = pPre;
}
}
free(pCur);
pCur = NULL;
--pL->_size;
return 0;
}
//查找
pNode_t list_find_val(pList_t pL, TYPENAME val)
{
if (list_empty(pL)) {
fprintf(stderr, "List is empty, cannot find!\n");
return NULL;
}
for (pNode_t pCur = pL->_pHead; pCur; pCur = pCur->_pNext) {
if (val == pCur->_data) {
return pCur;
}
}
fprintf(stderr, "Not found!\n");
return NULL;
}
pNode_t list_find_pos(pList_t pL, int pos)
{
if (list_empty(pL)) {
fprintf(stderr, "List is empty, cannot find!\n");
return NULL;
}
if (pos < 0 || pos > pL->_size) {
fprintf(stderr, "Find_pos is illegal!\n");
return NULL;
}
int i = 1;
pNode_t pCur = pL->_pHead;
for (; pCur; pCur = pCur->_pNext) {
if (i == pos) {
break;
}
++i;
}
return pCur;
}
//修改
int list_modify_val(pList_t pL, TYPENAME oldval, TYPENAME newval)
{
pNode_t ret = list_find_val(pL, oldval);
if (NULL == ret) {
return -1;
}
ret->_data = newval;
return 0;
}
int list_modify_pos(pList_t pL, int pos, TYPENAME newval)
{
pNode_t ret = list_find_pos(pL, pos);
if (NULL == ret) {
return -1;
}
ret->_data = newval;
return 0;
}
//展示链表
void list_show(pList_t pL)
{
if (list_empty(pL)) {
fprintf(stderr, "List is empty, cannot show!\n");
return;
}
for (pNode_t pCur = pL->_pHead; pCur; pCur = pCur->_pNext) {
printf("%d ", pCur->_data);
}
printf("\n");
return;
}
//得到链表长度
int list_size(pList_t pL)
{
if (pL) {
return pL->_size;
}
else {
return 0;
}
}
测试文件 test_list.c
#include "list.h"
#include <stdio.h>
int main()
{
int arr[] = {3, 5, 7, 8, 9, 6};
List_t L;
printf("\n-------------test list_init-----------\n");
/* list_init(&L); */
list_init_arr(&L, &arr[0], &arr[5]);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_headInsert-----------\n");
list_headInsert(&L, 20);
list_headInsert(&L, 20);
list_headInsert(&L, 30);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_tailInsert-----------\n");
list_tailInsert(&L, 40);
list_tailInsert(&L, 50);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_sortInsert-----------\n");
list_sortInsert(&L, 1);
list_sortInsert(&L, 100);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_erase_val-----------\n");
list_erase_val(&L, 20);
list_erase_val(&L, 200);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_erase_pos-----------\n");
list_erase_pos(&L, 1);
list_erase_pos(&L, 100);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
#if 0
printf("\n-------------test list_modify_val-----------\n");
list_modify_val(&L, 1, 88);
list_modify_val(&L, 30, 99);
list_modify_val(&L, 100, 99);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
printf("\n-------------test list_modify_pos-----------\n");
list_modify_pos(&L, 1, 88);
list_modify_pos(&L, 30, 99);
list_modify_pos(&L, list_size(&L), 66);
list_show(&L);
printf("list_size: %d\n", list_size(&L));
#endif
printf("\n");
list_destroy(&L);
/* list_show(&L); */
return 0;
}