数据结构-单向链表两个版本
2017-09-14 14:04
417 查看
链表一
思路:用一个结构体做链表头,里面统计链表的大小,获取这个链表头就是获取整个链表
链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储)
链表的优点:
1 不需要一块连续的存储区域
2 删除和插入某个元素效率高
缺点:随机访问元素效率低
linklist.h
linklist.c
main.c
打印结果:
链表二
版本二比版本一好一些,版本一要每次都要在堆上开辟节点空间,而版本二不用,版本二是直接让节点的前四个字节保存下一个节点的地址,形成链表
LinkList.h
main.c
打印结果:
思路:用一个结构体做链表头,里面统计链表的大小,获取这个链表头就是获取整个链表
链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储)
链表的优点:
1 不需要一块连续的存储区域
2 删除和插入某个元素效率高
缺点:随机访问元素效率低
linklist.h
#pragma once #include<stdlib.h> //链表节点 typedef struct LINKNODE { void* data;//数据域 struct LINKNODE* next;//指针域 }LinkNode; //链表 typedef struct LINKLIST { LinkNode header;//头节点 int size;//链表大小 }LinkList; //比较函数指针 typedef int(*COMPARE)(void* data1, void* data2); //打印函数指针 typedef void(*PRINT)(void* data); //初始化 void* Init_ListLink(); //指定位置插入 void Inset_ListLink(void* list,int pos,void* data); //头部插入操作 void PushFront_LinkList(void* list, void* data); //尾部插入操作 void PushBack_LinkList(void* list, void* data); //指定位置删除 void RemoveByPos_LinkList(void* list, int pos); //头部删除操作 void PopFront_LinkList(void* list); //尾部删除操作 void PopBack_LinkList(void* list); //值删除 void RemoveByVal_LinkList(void* list, void* data, COMPARE compare); //获得指定位置元素 void* Get_LinkList(void* list, int pos); //链表大小 int Size_LinkList(void* list); //遍历链表 void Print_LinkList(void* list, PRINT print); //销毁链表 void Destroy_LinkList(void* list);
linklist.c
#include "linklist.h" //初始化 void* Init_ListLink() { LinkList* list = (LinkList*)malloc(sizeof(LinkList)); list->size = 0; list->header.next = NULL; return list; } //指定位置插入 void Inset_ListLink(void* list, int pos, void* data) { if (NULL == list) { return; } if (NULL == data) { return; } LinkList* linklist = (LinkList*)list; //判断指定位置是否越界,越界默认尾部插入 if (pos<0 || pos>linklist->size) { pos = linklist->size; } //查找位置 LinkNode* pCurrent = &(linklist->header); int i = 0; for (; i < pos; ++i) { pCurrent = pCurrent->next;//跳到链表的下一个节点,直到指定位置 } //创建新节点 LinkNode* NewNode = (LinkList*)malloc(sizeof(LinkNode)); NewNode->data = data; NewNode->next = NULL; //新节点入链表 NewNode->next = pCurrent->next; pCurrent->next = NewNode; ++linklist->size; } //头部插入操作 void PushFront_LinkList(void* list, void* data) { if (NULL == list) { return; } if (NULL == data) { return; } Inset_ListLink(list, 0, data); } //尾部插入操作 void PushBack_LinkList(void* list, void* data) { if (NULL == list) { return; } if (NULL == data) { return; } LinkList* linklist = (LinkList*)list; Inset_ListLink(linklist, linklist->size, data); } //指定位置删除 void RemoveByPos_LinkList(void* list, int pos) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; if (po 4000 s < 0 || pos >= linklist->size)//第一个链表从0开始算 { return; } //判断链表是否为空 if (linklist->size == 0){ return; } //查找删除节点的前一个节点 LinkNode* pCurrent = &(linklist->header); int i = 0; for (; i < pos; i++) { pCurrent = pCurrent->next; } //缓存待删除节点 LinkNode* pDel = pCurrent->next; //重新连接被删除节点前驱和后继节点 pCurrent->next = pDel->next; //释放被删除节点内存 free(pDel); --linklist->size; } //头部删除操作 void PopFront_LinkList(void* list) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; if (linklist->size == 0) { return; } RemoveByPos_LinkList(linklist, 0); } //尾部删除操作 void PopBack_LinkList(void* list) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; if (linklist->size == 0) { return; } RemoveByPos_LinkList(linklist,linklist->size-1); } //值删除 void RemoveByVal_LinkList(void* list, void* data, COMPARE compare) { if (NULL == list) { return; } if (NULL == data ) { return; } LinkList* linklist = (LinkList*)list; if (linklist->size == 0) { return; } LinkNode* pCurrent = linklist->header.next; int i = 0; for (; i < linklist->size;++i) { if (compare(pCurrent->data, data)) { RemoveByPos_LinkList(list, i); return; } pCurrent = pCurrent->next; } } //获得指定位置元素,从0开始 void* Get_LinkList(void* list, int pos) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; if (linklist->size == 0) { return; } //遍历到指定位置的前一个节点 LinkNode* pCurrent = &(linklist->header); int i = 0; for (; i < pos; ++i) { pCurrent = pCurrent->next; } return pCurrent->next->data;//返回指定位置 } //链表大小 int Size_LinkList(void* list) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; return linklist->size; } //销毁链表 void Destroy_LinkList(void* list) { if (NULL == list) { return; } LinkList* linklist = (LinkList*)list; if (linklist->size == 0) { return; } LinkNode* pCurrent = linklist->header.next; while (pCurrent != NULL) { LinkNode* pnext = pCurrent->next; free(pCurrent); pCurrent = pnext; } free(linklist); printf("链表内存释放\n"); } //遍历链表 void Print_LinkList(void* list, PRINT print) { if (NULL == list) { return; } //拿到链表头 LinkList* linklist = (LinkList*)list; LinkNode* pCurrent = linklist->header.next;//指向第一个链表 while (pCurrent != NULL) { print(pCurrent->data); pCurrent = pCurrent->next; } }
main.c
#include "linklist.h" #include<string.h> typedef struct PERSON { char name[64]; int age; }person; void Print(void* data) { person* p = (person*)data; printf("name:%s,age:%d\n",p->name,p->age); } int conpare(void* data1, void* data2) { person* p1 = (person*)data1; person* p2 = (person*)data2; return strcmp(p1->name, p2->name) == 0 && p1->age == p2->age; } int main() { person p1 = { "aaaa", 1 }; person p2 = { "bbbb", 2 }; person p3 = { "cccc", 3 }; person p4 = { "dddd", 4 }; person p5 = { "eeee", 5 }; person p6 = { "ffff", 6 }; LinkList* list = Init_ListLink(); //头部插入操作 PushFront_LinkList(list, &p3); PushFront_LinkList(list, &p2); PushFront_LinkList(list, &p1); //指定位置插入 Inset_ListLink(list, 3, &p4); Inset_ListLink(list, 4, &p5); Inset_ListLink(list, 5, &p6); //打印 Print_LinkList(list, Print); printf("----------------------\n"); //指定位置删除 RemoveByPos_LinkList(list, 0); RemoveByPos_LinkList(list, 1); Print_LinkList(list, Print); printf("----------------------\n"); //头部删除操作 PopFront_LinkList(list); PopFront_LinkList(list); Print_LinkList(list, Print); printf("----------------------\n"); //值删除 RemoveByVal_LinkList(list, &p5, conpare); Print_LinkList(list, Print); printf("----------------------\n"); //获得指定位置元素 person* p= Get_LinkList(list, 0); printf("name:%s,age:%d\n", p->name, p->age); Destroy_LinkList(list); getchar(); }
打印结果:
链表二
版本二比版本一好一些,版本一要每次都要在堆上开辟节点空间,而版本二不用,版本二是直接让节点的前四个字节保存下一个节点的地址,形成链表
LinkList.h
#pragma once #include<stdlib.h> #include<stdio.h> #include<string.h> //链表小节点 typedef struct LINKNODE { struct LINKNODE* next; }LinkNode; //链表头节点 typedef struct LINKLIST { LinkNode header;//等价于struct LINKNODE* next;用结构体变量的话是为了更好的扩展性,如果是双向链表直接在结果体内加一个指针域 int size; }LinkList; typedef void* LLink; //比较函数指针 typedef int(*DataCompare)(LinkNode* data1, LinkNode* data2); //打印函数指针 typedef void(*DatePrint)(LinkNode* data); //初始化链表头 LLink Init_LinkList(); //指定位置插入 void Inset_ListLink(LLink* list, int pos, LinkNode*data); //头部插入操作 void PushFront_LinkList(LLink* list, LinkNode*data); //尾部插入操作 void PushBack_LinkList(LLink* list, LinkNode*data); //指定位置删除 void RemoveByPos_LinkList(LLink list, int pos); //头部位置删除 void PopFront_LinkList(LLink list); //尾部位置删除 void PopBack_LinkList(LLink list); //根据值删除 void RemoveByVal_LinkList(LLink list, LinkNode* data, DataCompare compare); //链表大小 int Size_LinkList(LLink list); //打印链表 void Print_LinkList(LLink list, DatePrint Print); //销毁链表 void Destroy_LinkList(LLink list);LinkList.c
#include"LinkList.h" //初始化链表头 LLink Init_LinkList() { LinkList* list = (LinkList*)malloc(sizeof(LinkList)); if (NULL == list) { printf("list malloc error\n"); return NULL; } list->header.next = NULL; list->size = 0; return list; } //指定位置插入 void Inset_ListLink(LLink* list, int pos, LinkNode*data) { if (NULL == list) { printf("Inset_ListLink list is NULL\n"); return; } if (NULL == data) { printf("Inset_ListLink data is NULL\n"); return; } LinkList* link_list = (LinkList*)list; if (pos<0 || pos>link_list->size)//如果越界就尾部插入 { pos = link_list->size; } //判断数据是否重复插入 #if 0 LinkNode* PRepeat = link_list->header.next; while (PRepeat != NULL) { if (PRepeat == data) { printf("数据重复插入\n"); return; } PRepeat = PRepeat->next; } #endif //辅助指针变量 LinkNode* Pcurrent = &(link_list->header); int i = 0; for (; i < pos; ++i) { Pcurrent = Pcurrent->next; } //新节点入链表 data->next = Pcurrent->next; Pcurrent->next = data; ++link_list->size; } //头部插入操作 void PushFront_LinkList(LLink* list, LinkNode*data) { if (NULL == list) { printf("PushFront_LinkList list is NULL\n"); return; } if (NULL == data) { printf("PushFront_LinkList data is NULL\n"); return; } Inset_ListLink(list, 0, data); } //尾部插入操作 void PushBack_LinkList(LLink* list, LinkNode*data) { if (NULL == list) { printf("PushBack_LinkList list is NULL\n"); return; } if (NULL == data) { printf("PushBack_LinkList data is NULL\n"); return; } LinkList* link_list = (LinkList*)list; Inset_ListLink(link_list, link_list->size, data); } //指定位置删除 void RemoveByPos_LinkList(LLink list, int pos) { if (NULL == list) { printf("RemoveByPos_LinkList list is NULL\n"); return; } LinkList* link_list = (LinkList*)list; if (pos < 0 || pos >= link_list->size) { printf("RemoveByPos_LinkList Transboundary\n"); return; } //辅助指针变量,找到删除节点的前一个节点,节点从0开始算 LinkNode* Pcurrent = &(link_list->header); int i = 0; for (; i < pos; ++i) { Pcurrent = Pcurrent->next; } //缓存要删除的节点 LinkNode* PDel = Pcurrent->next; Pcurrent->next = PDel->next; --link_list->size; } //头部位置删除 void PopFront_LinkList(LLink list) { if (NULL == list) { printf("PopFront_LinkList list is NULL\n"); return; } RemoveByPos_LinkList(list, 0); } //尾部位置删除 void PopBack_LinkList(LLink list) { if (NULL == list) { printf("PopBack_LinkList list is NULL\n"); return; } LinkList* link_list = (LinkList*)list; RemoveByPos_LinkList(link_list, link_list->size - 1); } //根据值删除 void RemoveByVal_LinkList(LLink list, LinkNode* data, DataCompare compare) { if (NULL == list) { printf("RemoveByVal_LinkList list is NULL\n"); return; } if (NULL == data) { printf("RemoveByVal_LinkList data is NULL\n"); return; } LinkList* link_list = (LinkList*)list; LinkNode* PDel = &(link_list->header); LinkNode* Pcurrent = PDel->next; while (Pcurrent != NULL) { if (compare(Pcurrent, data)) { PDel->next = Pcurrent->next; --link_list->size; break; } PDel = Pcurrent; Pcurrent = Pcurrent->next; } } //链表大小 int Size_LinkList(LLink list) { if (NULL == list) { printf("Size_LinkList list is NULL\n"); return; } LinkList* link_list = (LinkList*)list; return link_list->size; } //打印链表 void Print_LinkList(LLink list, DatePrint Print) { if (NULL == list) { printf("Print_LinkList list is NULL\n"); return; } LinkList* link_list = (LinkList*)list; LinkNode* Pcurrent = link_list->header.next; while (Pcurrent != NULL) { Print(Pcurrent); Pcurrent = Pcurrent->next; } } //销毁链表 void Destroy_LinkList(LLink list) { if (NULL == list) { printf(" Destroy_LinkList list is NULL\n"); return; } free(list); }
main.c
#include"LinkList.h" #include <stdio.h> typedef struct PERSON { LinkNode header;//一定要有这个节点,这个变量保持下一个数据的地址,如果没有的话数据会错乱 char name[64]; int age; }person; //比较函数指针 int Compare(LinkNode* data1, LinkNode* data2) { person* p1 = (person*)data1; person* p2 = (person*)data2; return strcmp(p1->name, p2->name)==0 && p1->age == p2->age; } //打印函数指针 void Print_list(LinkNode* data) { person* p1 = (person*)data; printf("Name:%s,Age:%d\n", p1->name, p1->age); } int main() { person p1 = { NULL, "aaa", 10 }; person p2 = { NULL, "bbb", 20 }; person p3 = { NULL, "ccc", 30 }; person p4 = { NULL, "ddd", 40 }; person p5 = { NULL, "eee", 50 }; LLink* list = Init_LinkList(); //指定位置删除 Inset_ListLink(list, 0, (LinkNode*)&p1); Inset_ListLink(list, 1, (LinkNode*)&p2); Inset_ListLink(list, 2, (LinkNode*)&p3); Inset_ListLink(list, 3, (LinkNode*)&p4); Inset_ListLink(list, 4, (LinkNode*)&p5); Print_LinkList(list, Print_list); printf("----------------------------------\n"); //指定位置删除 RemoveByPos_LinkList( list,2); RemoveByPos_LinkList(list, 2); //头部位置删除 PopFront_LinkList(list); //根据值删除 RemoveByVal_LinkList(list, (LinkNode*)&p5, Compare); Print_LinkList(list, Print_list); //链表大小 int size=Size_LinkList(list); printf("Size=%d\n",size); Destroy_LinkList(list); getchar(); return 0; }
打印结果:
相关文章推荐
- 数据结构之链表面试题汇总(四)得到两个单链表相交的第一个交点、用O(1)的时间效率删除单向链表中的指定节点
- 数据结构之设置尾指针的单向循环链表(参考整理严蔚敏数据结构)
- 判断两个单向链表是否相交
- 两个有序单向链表的合并
- Python实现基础数据结构--单向链表
- 第六十二题(求两个单向链表的第一个公共节点)
- 数据结构练习--单向链表的实现
- 题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。
- 判断单链表是否有环并找到入口处以及判断两个单向链表是否相交
- 合并两个排序的链表使之依然有序(不开辟新空间在原链表上操作的非递归版本)
- 数据结构(2):单向链表的反转
- 数据结构之链表与数组(三)-单向链表上的简单操作
- 数据结构~~单向链表
- 两个单向链表相交,找到第一个公共节点
- C 工具库 GLib --- 提供多种高级的数据结构,如内存块、双向和单向链表、哈希表、动态字符串等
- 数据结构 反转单向链表和双向链表
- 如何判断两个单向链表是否有相交,并找出交点
- 单向链表常用操作,C和C++版本(转载)
- 数据结构:线性表的链式存储(单向链表)--Java实现
- ※数据结构※→☆线性表结构(list)☆============单向循环链表结构(list circular single)(四)