C数据结构-线性表之单链表
来源:互联网 发布:吴京票房号召力知乎 编辑:程序博客网 时间:2024/05/15 01:36
线性表之单链表
单链表的设计之初,笔者在考虑一个首要的问题,就是单链表的节点是在插入的函数内部创建,还是在函数外部创建。考虑到用户在插入的时候,变量生命周期的不确定性以及容易造成内存泄漏等问题,综合考虑之下使用了内部创建节点的方式。笔者设计的单链表中包含了单链表的反转和合并等有趣的操作,其中的奥妙如果读者有兴趣可以细究。比如为什么笔者使用了二级指针来合并单链表,而不直接使用一级指针,比如为什么在清空链表节点时,根据length清空会有可能会发生内存泄漏....等等。下面是代码:
#ifndef LINKEDLIST_H#define LINKEDLIST_H#ifndef NULL#define NULL 0#endif/* 元素类型 */typedef int elem_t;/* 节点结构体 */typedef struct _tag_linked_list_node{ elem_t data; struct _tag_linked_list_node *next;}ll_node;/* 链表结构体 */typedef struct _tag_linked_list{ ll_node head; /* 哑结点 */ int length; /* 链表长度 */}linked_list;/** * 创建链表 * @return 返回链表指针,NULL表示创建失败 */linked_list *linked_list_create();/** * 从头部插入元素 * @param plist 链表指针 * @param pe 被插入元素的指针 * @return 1:成功 0:失败 */int linked_list_insert(linked_list *plist,elem_t *pe);/** * 从尾部插入元素 * @param plist 链表指针 * @param pe 被插入元素的指针 * @return 1:成功 0:失败 */int linked_list_append(linked_list *plist,elem_t *pe);/** * 查找元素 * @param plist 链表指针 * @param i 元素位置索引 * @param pe 用于保存被查找元素的值的指针 * @return 1:成功 0:失败 */int linked_list_get(linked_list *plist,int i,elem_t *pe);/** * 按索引删除元素 * @param plist 链表指针 * @param i 被删除元素的索引 * @param pe 用于保存被删除元素的值的指针 * @return 1:成功 0:失败 */int linked_list_remove(linked_list *plist,int i,elem_t *pe);/** * 链表反转 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_reverse(linked_list *plist);/** * 链表合并,将第二个链表链接到第一个链表,第二个链表指针置空 * @param dest 合并的目标链表 * @param pp_src 被合并的链表的指针的指针 * @return 返回合并后的链表的指针(第一个参数) */linked_list *linked_list_merge(linked_list *dest,linked_list **pp_src);/** * 清空链表 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_clear(linked_list *plist);/** * 销毁链表 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_destroy(linked_list *plist);#endif // LINKEDLIST_H
#include "LinkedList.h"#include <malloc.h>/** * 创建链表 * @return 返回链表指针,NULL表示创建失败 */linked_list *linked_list_create(){ linked_list *plist = (linked_list *)malloc(sizeof(linked_list)); if(plist != NULL) { plist->length = 0; plist->head.next = NULL; } return plist;}/** * 从头部插入元素 * @param plist 链表指针 * @param pe 被插入元素的指针 * @return 1:成功 0:失败 */int linked_list_insert(linked_list *plist,elem_t *pe){ int ret = ( (plist != NULL) && (pe != NULL)); if(ret) { ll_node *node = (ll_node *)malloc(sizeof(ll_node)); ll_node *head = &(plist->head); if(node != NULL) { node->next = head->next; head->next = node; node->data = *pe; plist->length++; } else { ret = 0; } } return ret;}/** * 从尾部插入元素 * @param plist 链表指针 * @param pe 被插入元素的指针 * @return 1:成功 0:失败 */int linked_list_append(linked_list *plist,elem_t *pe){ int ret = ( (plist != NULL) && (pe != NULL)); if(ret) { ll_node *node = (ll_node *)malloc(sizeof(ll_node)); if(node != NULL) { int pos = 0; ll_node *current = &(plist->head); /* 移动到尾部 */ for(pos = 0;pos < plist->length;pos++) { current = current->next; } node->next = NULL; node->data = *pe; current->next = node; plist->length++; } else { ret = 0; } } return ret;}/** * 查找元素 * @param plist 链表指针 * @param i 元素位置索引 * @param pe 用于保存被查找元素的值的指针 * @return 1:成功 0:失败 */int linked_list_get(linked_list *plist,int i,elem_t *pe){ int ret = ( (plist != NULL) && (pe != NULL) && (i >= 0) && (i < plist->length)); if(ret) { int pos = 0; ll_node *current = plist->head.next; /* 移动到尾部 */ for(pos = 0;pos < i;pos++) { current = current->next; } *pe = current->data; } return ret;}/** * 按索引删除元素 * @param plist 链表指针 * @param i 被删除元素的索引 * @param pe 用于保存被删除元素的值的指针 * @return 1:成功 0:失败 */int linked_list_remove(linked_list *plist,int i,elem_t *pe){ int ret = ( (plist != NULL) && (pe != NULL) && (i >= 0) && (i < plist->length)); if(ret) { int pos = 0; ll_node *pre = &(plist->head); for(pos = 0;pos < i;pos++) { pre = pre->next; } /* 保存要被删除的元素的值 */ *pe = pre->next->data; pre->next = pre->next->next; plist->length--; } return ret;}/** * 链表反转 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_reverse(linked_list *plist){ int ret = (plist != NULL); if(ret) { if(plist->length > 1) { int i; /* 保存尾元素的指针 */ ll_node *tail = &(plist->head); for(i = 0;i < plist->length;i++) { tail = tail->next; } /* 将头元素的位置调整到原尾元素的后部插入 */ while(plist->head.next != tail) { /* 保存头部元素的指针 */ ll_node *old_head = plist->head.next; /* 调整头结点指针的位置,指向原头部的下一个元素 */ plist->head.next = old_head->next; /* 将保存的原头部元素插入到原尾部元素的后面 */ old_head->next = tail->next; tail->next = old_head; } } } return ret;}/** * 链表合并,将第二个链表链接到第一个链表,第二个链表指针置空 * @param dest 合并的目标链表 * @param pp_src 被合并的链表的指针的指针 * @return 返回合并后的链表的指针(第一个参数) */linked_list *linked_list_merge(linked_list *dest,linked_list **pp_src){ if((dest != NULL) && ( (*pp_src) != NULL) && ((*pp_src)->length != 0)) { int i; ll_node *current = &(dest->head); /* 移动到目标链表的尾部元素 */ for(i = 0;i < dest->length;i++) { current = current->next; } current->next = (*pp_src)->head.next; dest->length += (*pp_src)->length; free(*pp_src); *pp_src = NULL; } return dest;}/** * 清空链表 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_clear(linked_list *plist){ int ret = ((plist != NULL) && (plist->length != 0)); if(ret) { /* * 这种清空的循环不妥,当外部恶意修改了plist->length,那么将会发生内存泄漏 int i; for(i = 0;i < plist->length;i++) { ll_node *del = plist->head.next; plist->head.next = del->next; free(del); } */ ll_node *head = &(plist->head); while(head->next != NULL) { ll_node *del = head->next; head->next = del->next; free(del); } plist->length = 0; } return ret;}/** * 销毁链表 * @param plist 链表指针 * @return 1:成功 0:失败 */int linked_list_destroy(linked_list *plist){ int ret = (plist != NULL); if(ret) { linked_list_clear(plist); free(plist); } return ret;}
阅读全文
0 0
- C数据结构-线性表之单链表
- 数据结构之线性表(C#)
- C数据结构-线性表之顺序表
- C语言数据结构之线性表
- C语言数据结构之线性表
- C语言数据结构之线性表(续)
- 数据结构C语言版之线性表
- 数据结构之线性表(C++)---数组描述
- 数据结构之线性表(C语言版)
- 数据结构:线性表之单链表
- 数据结构线性表之单链表
- 数据结构:线性表之单链表
- 数据结构-线性表之单链表
- 数据结构-线性表 (C++)
- 数据结构线性表c
- C - 数据结构 - 线性表
- 数据结构之线性表
- 数据结构之线性表
- javaweb接口安全校验预备知识——spring aop之 配置方式
- 浅谈CSRF攻击方式
- 转眼又是一年国庆节和中秋节,假日好好休息一下,不想太累!
- css定位
- HDU 1596 find the safest road
- C数据结构-线性表之单链表
- 使用Artifactory搭建私有Maven仓库
- 深度学习 ubuntu16.04 theano tensorflow cuda cudnn 搭建gpu加速,亲测有效
- mysql中通过时间/日期/时间日期类型条件查询
- jar命令的用法详解
- 0929 Spring框架
- 第四周项目5---猴子选大王
- java按字节、字符、行、随机读取文件,并设置字符编码格式
- 项目结构