【C-数据结构】单向链表,不带头节点(int)

概述


单向链表特点

  1. 只能顺序查找,时间复杂度O(n)
  2. 增加和删除操作开销小,适用于频繁增删的场景



设计数据结构

链表节点

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;



单向链表的相关操作

  1. 初始化
  2. 判空
  3. 销毁(销毁堆空间)
  4. 插入(头插、尾插、有序插入)
  5. 删除(按值删除、按位删除)
  6. 查找(按值查找、按位查找)
  7. 修改(按值修改、按位修改)



操作实现思路


初始化(参数:链表地址)

  1. 头尾指针置为空



判空(参数:链表地址)

  1. 头指针 == NULL



销毁(参数:链表地址)

  1. 非空时,遍历链表,挨个free节点



头插(参数:链表地址,插入值)

  1. 新建结点,初始化
  2. 链表为空时,头尾指针指向新节点
  3. 链表非空时,新节点指向头指针,重置头指针
  4. ++size



尾插(参数:链表地址,插入值)

  1. 新建结点,并初始化
  2. 链表为空时,头尾指针指向新节点
  3. 链表非空时,尾指针指向,重置尾指针
  4. ++size



有序插入(参数:链表地址,插入值)

  1. 新建结点,并初始化
  2. 链表为空时,头尾指针指向新节点
  3. 链表非空时,且新节点最小,头插
  4. 链表非空时,找第一个大于新节点的地址
    1. pPre指针(用来放新节点),pCur指针(用来找位置)
    2. 遍历链表,for (pPre = pList->_pHead, pCur = pPre->_pNext; pCur; pPre = pCur, pCur = pCur->_pNext)
      1. 找到第一个大于插入值的位置,将新节点连接pPre和pCur,break
    3. 如果NULL == pCur,表示没找到比新节点大的位置,尾插
  5. ++size


按值删除(参数:链表地址,待删除值)

  1. 如果链表为空,报错返回
  2. 如果链表非空,pCur遍历链表,找每一个待删除值的位置,pDel指向带删除值
    1. 保存待删除结点地址
    2. 如果是头节点,修改链表头指针
    3. 如果是尾结点,修改链表尾指针
    4. 修改相关指针,free待删除结点
    5. –size



按位删除(参数:链表地址,删除位置)

  1. 如果位置非法,报错返回
  2. 如果链表为空,报错返回
  3. 如果链表非空,遍历链表,找到位置,pDel指向带删除值
    1. 保存待删除结点地址
    2. 如果是第一个元素,修改表头指针
    3. 如果是最后一个元素,修改表尾指针
    4. 修改相关指针,free待删除结点
    5. –size



按值查找(参数:链表地址,待查询值)

  1. 如果链表为空,报错返回
  2. 遍历链表,找到返回地址,没找到返回NULL



按位查找(参数:链表地址,待查询位置)

  1. 如果链表为空,报错返回
  2. 如果位置非法,报错返回
  3. 遍历链表,找到返回地址,没找到返回NULL



按值修改(参数:链表地址,待修改值)

  1. 如果链表为空,报错返回
  2. 遍历链表,找到就修改,没找到返回NULL



按位修改(参数:链表地址,待修改位置)

  1. 如果链表为空,报错返回
  2. 如果位置非法,报错返回
  3. 遍历链表,找到就修改,没找到返回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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值