数据结构链表

1.概念

逻辑结构:线性结构

存储结构:链式结构

链表又分为有头节点和无头节点的,每种又细分为单向的,循环的,双向的。

以单向链表为例。

有头节点单向链表示意图:

2.对链表的操作

1.创建链表节点 √

2.清空链表 √

3.销毁链表 √

4.向链表中插入元素(头插) √

5.向链表中插入元素(尾插) √

6.向链表中插入元素(任意位置插入) √

7.在链表中删除元素(头删) √

8.在链表中删除元素(尾删) √

9.在链表中删除元素(任意位置删除) √

10.修改链表中指定位置的元素 √

11.查找链表中指定位置的元素 √

12.两个链表的合并 √

13.链表的排序 √

14.链表的翻转 √

15.链表的剔重 √

16.遍历打印链表中所有元素----看现象用的 √

3.链表操作流程图

(1)链表插入节点流程图

(2)链表删除节点流程图

(3)两个链表合并的流程图

(4)链表翻转流程图

(5)链表排序流程图

也是采用冒泡排序的思想

(6)链表剔重流程图

4.代码实现

link_list.h

#ifndef __LINK_LIST_H__
#define __LINK_LIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//链表节点的结构体
typedef struct _Node{
    int data;           //数据域 此处以int为例 实际使用时用实际类型替换即可
    struct _Node *next; //指针域 此处不能使用 node_t 因为还不认识呢
}node_t;

int create_node(node_t **p, int data);
int insert_list_by_head(node_t *phead, int data);
int print_list(node_t *phead);
int insert_list_by_tail(node_t *phead, int data);
int insert_list_by_pos(node_t *phead, int pos, int data);
int delete_list_by_head(node_t *phead);
int delete_list_by_tail(node_t *phead);
int delete_list_by_pos(node_t *phead, int pos);
int modify_list_by_pos(node_t *phead, int pos, int new_data);
int search_list_by_pos(node_t *phead, int pos, int *num);
int clean_list(node_t *phead);
int destroy_list(node_t **phead);
int merge_list(node_t *phead1, node_t **phead2);
int reverse_list(node_t *phead);
int sort_list(node_t *phead);
int tichong_list(node_t *phead);

#endif

link_list.c

#include "link_list.h"

//创建链表节点的函数
int create_node(node_t **p, int data){
    if(NULL == p){
        printf("入参为NULL\n");
        return -1;
    }
    *p = (node_t *)malloc(sizeof(node_t));
    if(NULL == *p){
        printf("内存分配失败\n");
        return -1;
    }
    //初始化新节点
    (*p)->data = data;
    (*p)->next = NULL;
    return 0;
}

//向链表中插入元素(头插)
int insert_list_by_head(node_t *phead, int data){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    node_t *pnew = NULL;
    create_node(&pnew, data);
    //执行头插操作
    pnew->next = phead->next;
    phead->next = pnew;
    return 0;
}

//遍历链表
int print_list(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    node_t *ptemp = phead;//备份一下头结点
                        //防止函数内部后面使用时 找不到链表头了
    while(NULL != ptemp->next){
        ptemp = ptemp->next;
        printf("%d  ", ptemp->data);
    }
    printf("\n");
    return 0;
}

//向链表中插入元素(尾插)
int insert_list_by_tail(node_t *phead, int data){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    //先遍历链表 找到最后一个节点
    node_t *ptemp = phead;
    while(NULL != ptemp->next){
        ptemp = ptemp->next;
    }
    node_t *pnew = NULL;
    create_node(&pnew, data);
    ptemp->next = pnew;
    return 0;
}

//向链表中插入元素(任意位置插入)
int insert_list_by_pos(node_t *phead, int pos, int data){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(pos < 0){
        printf("插入位置不合理 插入失败\n");
        return -1;
    }
    node_t *ptemp = phead;
    int i = 0;
    for(i = 0; i < pos; i++){
        ptemp = ptemp->next;
        if(NULL == ptemp){
            break;
        }
    }
    if(i < pos){
        printf("插入位置不合理 插入失败\n");
        return -1;
    }
    //执行插入操作
    node_t *pnew = NULL;
    create_node(&pnew, data);
    pnew->next = ptemp->next;
    ptemp->next = pnew;
    return 0;
}

//在链表中删除元素(头删)
int delete_list_by_head(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 删除失败\n");
        return -1;
    }
    node_t *pdel = phead->next;
#if 1
    phead->next = phead->next->next;
#else
    phead->next = pdel->next;
#endif
    free(pdel);
    pdel = NULL;
    return 0;
}

//在链表中删除元素(尾删)
int delete_list_by_tail(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 删除失败\n");
        return -1;
    }
    //遍历链表 找到倒数第二个数据节点
    node_t *ptemp = phead;
    while(NULL != ptemp->next->next){
        ptemp = ptemp->next;
    }
    free(ptemp->next);
    ptemp->next = NULL;
    return 0;
}

//在链表中删除元素(任意位置删除)
int delete_list_by_pos(node_t *phead, int pos){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 删除失败\n");
        return -1;
    }
    if(pos < 0){
        printf("删除位置不合理 删除失败\n");
        return -1;
    }
    node_t *ptemp = phead;
    int i = 0;
    for(i = 0; i < pos; i++){
        ptemp = ptemp->next;
        if(NULL == ptemp->next){
            break;
        }
    }
    if(i < pos){
        printf("删除位置不合理 删除失败\n");
        return -1;
    }
    //执行删除操作
    node_t *pdel = ptemp->next;
    ptemp->next = pdel->next;
    free(pdel);
    pdel = NULL;
    return 0;
}

//修改链表中指定位置的元素
int modify_list_by_pos(node_t *phead, int pos, int new_data){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 修改失败\n");
        return -1;
    }
    if(pos < 0){
        printf("修改位置不合理 修改失败\n");
        return -1;
    }
    node_t *ptemp = phead;
    int i = 0;
    for(i = 0; i < pos; i++){
        ptemp = ptemp->next;
        if(NULL == ptemp->next){
            printf("修改位置不合理 修改失败\n");
            return -1;
        }
    }
    //执行修改操作
    ptemp->next->data = new_data;
    return 0;
}

//查找链表中指定位置的元素
int search_list_by_pos(node_t *phead, int pos, int *num){
    if(NULL == phead || NULL == num){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 没有数据节点\n");
        return -1;
    }
    if(pos < 0){
        printf("查找的位置没有数据\n");
        return -1;
    }
    node_t *ptemp = phead;
    int i = 0;
    for(i = 0; i < pos; i++){
        ptemp = ptemp->next;
        if(NULL == ptemp->next){
            printf("查找的位置没有数据\n");
            return -1;
        }
    }
    //执行查找操作
    *num = ptemp->next->data;
    return 0;
}

//清空链表
int clean_list(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    //循环头删
    node_t *pdel = NULL;
    while(NULL != phead->next){
        pdel = phead->next;
        phead->next = pdel->next;
        free(pdel);
    }
    pdel = NULL;
    return 0;
}

//销毁链表
int destroy_list(node_t **phead){
    if(NULL == phead || NULL == *phead){
        printf("入参为NULL\n");
        return -1;
    }
    //为了防止内存泄漏 应该先清空再销毁
    clean_list(*phead);
    free(*phead);
    *phead = NULL;
    return 0;
}

//两个链表合并
int merge_list(node_t *phead1, node_t **phead2){
    if(NULL == phead1 || NULL == phead2 || NULL == *phead2){
        printf("入参为NULL\n");
        return -1;
    }
    node_t *ptemp = phead1;
    while(NULL != ptemp->next){
        ptemp = ptemp->next;
    }
    ptemp->next = (*phead2)->next;
    free(*phead2);
    *phead2 = NULL;
    return 0;
}

//链表的翻转
int reverse_list(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 无需翻转\n");
        return -1;
    }
    if(NULL == phead->next->next){
        printf("只有一个节点 无需翻转\n");
        return -1;
    }
    node_t *p = phead->next;
    node_t *q = p->next;
    p->next = NULL;
    while(NULL != p){
        p = q->next;
        q->next = phead->next;
        phead->next = q;
        q = p;
    }
    return 0;
}

//链表的排序  以升序为例
int sort_list(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 无需排序\n");
        return -1;
    }
    if(NULL == phead->next->next){
        printf("只有一个节点 无需排序\n");
        return -1;
    }
    node_t *p = phead->next;
    node_t *q = NULL;
    int temp = 0;
    while(NULL != p->next){
        q = p->next;
        while(NULL != q){
            if(p->data > q->data){
                temp = p->data;
                p->data = q->data;
                q->data = temp;
            }
            q = q->next;
        }
        p = p->next;
    }
    return 0;
}

//链表的剔重
int tichong_list(node_t *phead){
    if(NULL == phead){
        printf("入参为NULL\n");
        return -1;
    }
    if(NULL == phead->next){
        printf("链表为空 无需剔重\n");
        return -1;
    }
    if(NULL == phead->next->next){
        printf("只有一个节点 无需剔重\n");
        return -1;
    }
    node_t *p = phead->next;
    node_t *q = NULL;
    node_t *m = NULL;//用来保存q的前一节点 删除q时使用
    while(NULL != p){
        m = p;
        q = p->next;
        while(NULL != q){
            if(p->data == q->data){
                m->next = q->next;
                free(q);
                q = m->next;
            }else{
                m = q;
                q = q->next;
            }
        }
        p = p->next;
    }
    return 0;
}

main.c    调试用的

#include "link_list.h"

int main(int argc, const char *argv[])
{
    node_t *phead = NULL;
    create_node(&phead, -1);
    printf("phead = %p\n", phead);//非NULL

    //测试头插
    insert_list_by_head(phead, 10);
    insert_list_by_head(phead, 20);
    insert_list_by_head(phead, 30);
    print_list(phead); // 30 20 10

    //测试尾插
    insert_list_by_tail(phead, 40);
    insert_list_by_tail(phead, 50);
    insert_list_by_tail(phead, 60);
    print_list(phead); // 30 20 10 40 50 60

    //测试任意位置插入
    insert_list_by_pos(phead, 7, 100);//不合理
    insert_list_by_pos(phead, 6, 100);
    insert_list_by_pos(phead, 3, 200);
    print_list(phead); // 30 20 10 200 40 50 60 100

    //测试头删
    delete_list_by_head(phead);
    delete_list_by_head(phead);
    print_list(phead); // 10 200 40 50 60 100
    
    //测试尾删
    delete_list_by_tail(phead);
    delete_list_by_tail(phead);
    print_list(phead); // 10 200 40 50

    //测试任意位置删除
    delete_list_by_pos(phead, 4);//不合理
    delete_list_by_pos(phead, 3);
    delete_list_by_pos(phead, 1);
    print_list(phead); // 10 40

    //测试修改
    modify_list_by_pos(phead, 2, 20);//不合理
    modify_list_by_pos(phead, 1, 20);
    print_list(phead); // 10 20

    //测试查找
    int num = 0;
    search_list_by_pos(phead, 2, &num);//不合理
    search_list_by_pos(phead, 1, &num);
    printf("num = %d\n", num); //20

    //测试清空
    clean_list(phead);
    print_list(phead); // 没有元素了

    //测试销毁
    destroy_list(&phead);
    printf("phead = %p\n", phead);//NULL

    //测试合并
    create_node(&phead, -1);
    insert_list_by_tail(phead, 10);
    insert_list_by_tail(phead, 20);
    insert_list_by_tail(phead, 30);
    node_t *phead2 = NULL;
    create_node(&phead2, -1);
    insert_list_by_tail(phead2, 40);
    insert_list_by_tail(phead2, 50);
    insert_list_by_tail(phead2, 60);
    merge_list(phead, &phead2);
    print_list(phead); // 10 20 30 40 50 60
    printf("phead2 = %p\n", phead2);//NULL

    //测试翻转
    reverse_list(phead);
    print_list(phead); // 60 50 40 30 20 10

    //测试排序
    sort_list(phead);
    print_list(phead); // 10 20 30 40 50 60

    //测试剔重
    insert_list_by_pos(phead, 2, 10);
    insert_list_by_pos(phead, 5, 10);
    insert_list_by_pos(phead, 7, 20);
    insert_list_by_tail(phead, 60);
    insert_list_by_tail(phead, 60);
    insert_list_by_tail(phead, 60);
    print_list(phead); // 10 20 10 30 40 10 50 20 60 60 60 60
    tichong_list(phead);
    print_list(phead); // 10 20 30 40 50 60

    destroy_list(&phead);

    return 0;
}
  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值