C语言实现单链表
2017-06-28 17:15
246 查看
单链表是一种链式存取的数据结构,,其中数据以节点来表示,每个节点由一个数据元素和一个指向后继元素存储位置的指针构成,在这里,我通过3个文件来编写单链表:list.h list.c test.c。
接下来实现PrintList函数(输出单链表),PrintList函数需要输入一个链表的指针,要输出所有的节点就要用到一个while循环,每次循环直接输出data,然后把指针置为next。
代码如下:
接下来实现PushBack函数(尾插),在链表尾部插入一个节点,本来应该直接传入一个链表的指针,但是考虑到如果传入的是一个空链表的指针,我们需要为该指针开辟一个空间来写入数据,就要改变该指针的值,如果直接传入该指针,我们只能改变该指针的形参的值,无法改变该指针的值,所以该函数应该传入链表指针的地址,即二级指针,如果传入的不是空链表,我们只需找到该链表的最后一个节点,为该节点的next开辟一个空间,将数据写进去就好了。
代码如下:
接下来实现PopBack函数(尾删),该函数也要传入一个二级指针,分为三种情况:
空链表:直接返回
链表只有一个节点:用free函数释放空间,并将链表指针置为空
链表含有多个节点:删除最后一个节点,并将前一个节点的next置为空,我们只需要用while循环,就可以很轻松的找到最后一个节点,难点在于将最后一个节点删除之后,如何找到前一个节点,在这里,我们可以创建两个指针p1,p2,始终让p2指向p1的下一个节点,这样但p2到达最后一个节点时,p1刚好指向上一个节点。
代码如下:
PushFront函数(头插)
1、单链表为空,直接调用BuyNode函数创建一个节点
2、单链表不为空,创建一个新的节点赋给链表第一个节点的指针,并将next指向链表原来的第一个节点,只需要创建一个临时指针变量接收原来第一个节点的地址就可以了。
代码如下:
PopFront函数(头删)
该函数依然需要传入二级指针,根据单
1032c
链表不同有三种情况:
1、单链表为空,这种情况我们直接return;
2、单链表只有一个节点,删除该节点,将链表指针置为空,
3、单链表含有多个节点,删除第一个节点,并将链表指针指向下个节点。
代码如下:
Find函数(查找)
该函数要求传入一个单链表指针和一个数据x,在单链表中找到x的位置。
我们只需要将单链表遍历一遍,在此过程中找到x则返回它的指针,遍历玩仍未找到返回NULL;
代码如下:
Insert函数(在pos的前面插入一个节点x)
1、单链表为空,return
2、pos是第一个节点,调用头插函数
3、pos不是第一个节点,创建一个节点,让pos的前一个节点指向该节点,并使该节点指向pos
代码如下:
Erase函数(删除指定节点)
1、单链表或pos为空,return
2、pos为第一个节点指针,调用头删函数
3、pos不是第一个节点指针,删除该节点,并使该节点上个节点指向该节点下个节点(如果是最后一个节点则指向NULL)
代码如下:
至此,所有的函数都已经实现了,完整的list.c源文件代码如下:
List.h
list.h中主要是一些函数声明,在这里就不做介绍了,直接粘代码:#define _CRT_SECURE_NO_WARNINGS 1 #ifndef __LIST_H__ #define __LIST_H__ #include <stdio.h> #include <assert.h> #include <malloc.h> typedef int DataType; //将int类型重命名,方便修改单链表的类型 typedef struct ListNode { DataType data; //元素 struct ListNode* next;//下个位置指针 }ListNode; ListNode* BuyNode(DataType x);//创建单链表 void PrintList(ListNode* pList);//输出单链表 void PushBack(ListNode** ppList, DataType x);//尾插 void PopBack(ListNode** ppList); //尾删 void PushFront(ListNode** ppList, DataType x); //头插 void PopFront(ListNode** ppList); //头删 ListNode* Find(ListNode* pList, DataType x);//查找 void Insert(ListNode** ppList, ListNode* pos, DataType x); // 在pos的前面插入一个节点x void Erase(ListNode** ppList, ListNode* pos);//删除指定节点 #endif
list.c
首先,我们来实现BuyNode函数(创建单链表),函数原型为ListNode* BuyNode(DataType x),传入一个DataType类型变量x,返回一个ListNode类型的指针,我们直接用malloc开辟一个空间,将x赋给Data,next置为空,再返回我们开辟的空间的指针就好了。代码如下:ListNode* BuyNode(DataType x) { ListNode *pList=(ListNode*)malloc(sizeof(ListNode)); pList->data=x; pList->next=NULL; return pList; }
接下来实现PrintList函数(输出单链表),PrintList函数需要输入一个链表的指针,要输出所有的节点就要用到一个while循环,每次循环直接输出data,然后把指针置为next。
代码如下:
void PrintList(ListNode* pList) { while(pList) { printf("%d->",pList->data); pList=pList->next; } printf("%s\n",pList);//此时pList为空,会输出(null) }
接下来实现PushBack函数(尾插),在链表尾部插入一个节点,本来应该直接传入一个链表的指针,但是考虑到如果传入的是一个空链表的指针,我们需要为该指针开辟一个空间来写入数据,就要改变该指针的值,如果直接传入该指针,我们只能改变该指针的形参的值,无法改变该指针的值,所以该函数应该传入链表指针的地址,即二级指针,如果传入的不是空链表,我们只需找到该链表的最后一个节点,为该节点的next开辟一个空间,将数据写进去就好了。
代码如下:
void PushBack(ListNode** ppList, DataType x) { //空 //非空 assert(ppList); if(*ppList==NULL) { *ppList=BuyNode(x); //当链表为空时,直接掉用BuyNode函数创建一个节点 } else { ListNode* pList=*ppList; while(pList->next) { pList=pList->next; //当pList->next为空时,pList指向最后一个节点 } pList->next=BuyNode(x); //直接调用BuyNode函数在当前位置创建一个新节点 } }
接下来实现PopBack函数(尾删),该函数也要传入一个二级指针,分为三种情况:
空链表:直接返回
链表只有一个节点:用free函数释放空间,并将链表指针置为空
链表含有多个节点:删除最后一个节点,并将前一个节点的next置为空,我们只需要用while循环,就可以很轻松的找到最后一个节点,难点在于将最后一个节点删除之后,如何找到前一个节点,在这里,我们可以创建两个指针p1,p2,始终让p2指向p1的下一个节点,这样但p2到达最后一个节点时,p1刚好指向上一个节点。
代码如下:
void PopBack(ListNode** ppList) { //空 //一个 //多个 assert(ppList); if(*ppList==NULL) return;//链表为空直接返回 else if((*ppList)->next ==NULL) { //只有一个节点 free(*ppList);//释放空间 *ppList=NULL;//链表指针置为空 } else//含有多个节点 { ListNode* p1=*ppList; ListNode* p2=p1->next ;//p2指p1下一个节点 while(p2->next)//p2指向最后一个节点时退出循环 { p1=p1->next ; p2=p2->next ; //p1,p2分别往后移动一个节点 } free(p2); p1->next =NULL; }
PushFront函数(头插)
1、单链表为空,直接调用BuyNode函数创建一个节点
2、单链表不为空,创建一个新的节点赋给链表第一个节点的指针,并将next指向链表原来的第一个节点,只需要创建一个临时指针变量接收原来第一个节点的地址就可以了。
代码如下:
void PushFront(ListNode** ppList, DataType x) { assert(ppList); //空 //非空 if(*ppList==NULL) *ppList=BuyNode(x); else { ListNode* p=*ppList; *ppList=BuyNode(x); (*ppList)->next =p; } }
PopFront函数(头删)
该函数依然需要传入二级指针,根据单
1032c
链表不同有三种情况:
1、单链表为空,这种情况我们直接return;
2、单链表只有一个节点,删除该节点,将链表指针置为空,
3、单链表含有多个节点,删除第一个节点,并将链表指针指向下个节点。
代码如下:
void PopFront(ListNode** ppList) { assert(ppList); if(*ppList==NULL)//空 return; else if((*ppList)->next ==NULL)//一个 { free(*ppList); *ppList=NULL; } else//多个 { ListNode* ptmp=*ppList; *ppList=(*ppList)->next ;//*ppList指向下个节点 free(ptmp);//删除首个节点 } }
Find函数(查找)
该函数要求传入一个单链表指针和一个数据x,在单链表中找到x的位置。
我们只需要将单链表遍历一遍,在此过程中找到x则返回它的指针,遍历玩仍未找到返回NULL;
代码如下:
ListNode* Find(ListNode* pList, DataType x) { while(pList) { if(pList->data ==x) return pList; pList=pList->next ; } return NULL; }
Insert函数(在pos的前面插入一个节点x)
1、单链表为空,return
2、pos是第一个节点,调用头插函数
3、pos不是第一个节点,创建一个节点,让pos的前一个节点指向该节点,并使该节点指向pos
代码如下:
void Insert(ListNode** ppList, ListNode* pos, DataType x) { assert(ppList); assert(pos); if(*ppList==NULL) return; else if(*ppList==pos) PushFront(ppList,x); else { ListNode* pList=*ppList; while((pList->next)!=pos) { pList=pList->next ; }//找到pos的前一个节点 pList->next =BuyNode(x); pList->next ->next =pos; } }
Erase函数(删除指定节点)
1、单链表或pos为空,return
2、pos为第一个节点指针,调用头删函数
3、pos不是第一个节点指针,删除该节点,并使该节点上个节点指向该节点下个节点(如果是最后一个节点则指向NULL)
代码如下:
void Erase(ListNode** ppList, ListNode* pos) { assert(ppList); if((*ppList==NULL)||(pos==NULL)) return; else if(*ppList==pos) PopFront(ppList); else { ListNode* pList=*ppList; while((pList)->next !=pos) { pList=pList->next ; //找到pos的前一个节点 } pList->next =pos->next ; free(pos); } }
至此,所有的函数都已经实现了,完整的list.c源文件代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"
ListNode* BuyNode(DataType x) { ListNode *pList=(ListNode*)malloc(sizeof(ListNode)); pList->data=x; pList->next=NULL; return pList; }
void PrintList(ListNode* pList) { while(pList) { printf("%d->",pList->data); pList=pList->next; } printf("%s\n",pList);//此时pList为空,会输出(null) }
void PushBack(ListNode** ppList, DataType x) { //空 //非空 assert(ppList); if(*ppList==NULL) { *ppList=BuyNode(x); //当链表为空时,直接掉用BuyNode函数创建一个节点 } else { ListNode* pList=*ppList; while(pList->next) { pList=pList->next; //当pList->next为空时,pList指向最后一个节点 } pList->next=BuyNode(x); //直接调用BuyNode函数在当前位置创建一个新节点 } }
void PopBack(ListNode** ppList) { //空 //一个 //多个 assert(ppList); if(*ppList==NULL) return;//链表为空直接返回 else if((*ppList)->next ==NULL) { //只有一个节点 free(*ppList);//释放空间 *ppList=NULL;//链表指针置为空 } else//含有多个节点 { ListNode* p1=*ppList; ListNode* p2=p1->next ;//p2指p1下一个节点 while(p2->next)//p2指向最后一个节点时退出循环 { p1=p1->next ; p2=p2->next ; //p1,p2分别往后移动一个节点 } free(p2); p1->next =NULL; }
}
void PushFront(ListNode** ppList, DataType x) { assert(ppList); //空 //非空 if(*ppList==NULL) *ppList=BuyNode(x); else { ListNode* p=*ppList; *ppList=BuyNode(x); (*ppList)->next =p; } }
void PopFront(ListNode** ppList) { assert(ppList); if(*ppList==NULL)//空 return; else if((*ppList)->next ==NULL)//一个 { free(*ppList); *ppList=NULL; } else//多个 { ListNode* ptmp=*ppList; *ppList=(*ppList)->next ;//*ppList指向下个节点 free(ptmp);//删除首个节点 } }
ListNode* Find(ListNode* pList, DataType x) { while(pList) { if(pList->data ==x) return pList; pList=pList->next ; } return NULL; }
void Insert(ListNode** ppList, ListNode* pos, DataType x) { assert(ppList); assert(pos); if(*ppList==NULL) return; else if(*ppList==pos) PushFront(ppList,x); else { ListNode* pList=*ppList; while((pList->next)!=pos) { pList=pList->next ; }//找到pos的前一个节点 pList->next =BuyNode(x); pList->next ->next =pos; } }
void Erase(ListNode** ppList, ListNode* pos)
{
assert(ppList);
if((*ppList==NULL)||(pos==NULL))
return;
else if(*ppList==pos)
PopFront(ppList);
else
{
ListNode* pList=*ppList;
while((pList)->next !=pos)
{
pList=pList->next ;
}
pList->next =pos->next ;
free(pos);
}
}
test.c
test.c文件用来验证编写的函数,自己检验即可,我的代码如下:#define _CRT_SECURE_NO_WARNINGS 1 #include "list.h" void test1()//验证BuyNode,PrintList { ListNode* pList=BuyNode(1); PrintList(pList);//1->(null) } void test2()//验证PushBack { //空 ListNode* pList=NULL; PushBack(&pList,1); PrintList(pList);//1 //非空 PushBack(&pList,2); PushBack(&pList,3); PushBack(&pList,4); PrintList(pList);//1->2->3->4->(null) } void test3()//验证PopBack { ListNode* pList=BuyNode(1); PushBack(&pList,2); PushBack(&pList,3); PushBack(&pList,4); PrintList(pList);//1->2->3->4->(null) PopBack(&pList); PrintList(pList);//1->2->3->(null) PopBack(&pList); PrintList(pList);//1->2->(null) PopBack(&pList); PrintList(pList);//1->(null) PopBack(&pList); PrintList(pList);//(null) PopBack(&pList); PrintList(pList);//(null) } void test4()//验证PushFront { //空 ListNode* pList=NULL; PushFront(&pList,1); PrintList(pList);//1->(null) //非空 PushFront(&pList,2);//2->1->(null) PrintList(pList); PushFront(&pList,3);//3->2->1->(null) PrintList(pList); PushFront(&pList,4);//4->3->2->1->(null) PrintList(pList); } void test5()//验证PopFront { ListNode* pList=BuyNode(1); PushBack(&pList,2); PushBack(&pList,3); PushBack(&pList,4); PrintList(pList);//1->2->3->4->(null) PopFront(&pList); PrintList(pList);//2->3->4->(null) PopFront(&pList); PrintList(pList);//3->4->(null) PopFront(&pList); PrintList(pList);//4->(null) PopFront(&pList); PrintList(pList);//(null) PopFront(&pList); PrintList(pList);//(null) } void test6()//验证Find,Insert { ListNode* p; ListNode* pList=BuyNode(1); PushBack(&pList,2); PushBack(&pList,3); PushBack(&pList,4); PrintList(pList);//1->2->3->4->(null) p=Find(pList,3);//3->4->(null) PrintList(p); p=Find(pList,2);//2->3->4->(null) PrintList(p); p=Find(pList,5);//(null) PrintList(p); p=Find(pList,1); Insert(&pList,p,5); PrintList(pList);//5->1->2->3->4->(null) p=Find(pList,3); Insert(&pList,p,6); PrintList(pList);//5->1->2->6->3->4->(null) } void test7()//验证Erase { ListNode* p; ListNode* pList=NULL; PushBack(&pList,1); PushBack(&pList,2); PushBack(&pList,3); PushBack(&pList,4); PrintList(pList);//1->2->3->4->(null) p=Find(pList,3); Erase(&pList,p); PrintList(pList);//1->2->4->(null) p=Find(pList,1); Erase(&pList,p); PrintList(pList);//2->4->(null) p=Find(pList,4); Erase(&pList,p); PrintList(pList);//2->(null) } int main() { //test1(); //test2(); //test3(); //test4(); //test5(); //test6(); test7(); return 0; }
相关文章推荐
- C语言单链表的建立,查找,添加,删除,修改功能实现
- 单链表操作演示----C语言实现
- 数据结构C语言之单链表简单实现
- 数据结构中单链表的实现+单链表的C语言实现源代码
- 单链表的C语言算法实现
- 顺序表的链式结构中用C语言实现单链表的交并差运算
- C语言实现有序单链表的插入
- 二、数据结构基础之单链表C语言实现
- 数据结构C语言单链表的实现和几点注意的问题
- C语言实现单链表的逆置
- C语言实现简单单链表
- 链表的C语言实现之单链表的实现
- C语言又一个单链表的实现
- 链表的C语言实现之单链表的实现
- c语言实现单链表的操作:创建,删除,插入,反转, 排序等
- 链表的C语言实现之单链表的实现
- C语言实现单链表的各种操作
- C语言实现单链表
- 自己编的C语言单链表的实现
- C语言实现单链表的逆置