> 文档中心 > 【C语言实现单链表】学会单链表多是一件美事啊,你确定不看看吗

【C语言实现单链表】学会单链表多是一件美事啊,你确定不看看吗

目录

一 单链表的基本概念

1.单链表的定义

2.区分两个概念

3.单链表的特点

二 单链表的表示

三 单链表的基本操作

1.单链表的初始化

2.单链表的创建

头插法

 尾插法

 3.单链表的插入

按位序插入

指定节点的后插操作

指定节点的前插操作

 4.单链表的删除

按位序删除

指定节点的删除

指定节点后的删除

 5.单链表的查找

按位查找

按值查找

 6.求表长


本文是我在复习 计算机基础--数据结构 的一些学习笔记,希望通过这样的方式,在掌握知识的同时,将我学到的东西分享给更多的人,能给他们带来帮助,我就很开心了。

若有志同道合之人,可以加入我,一起学习计算机知识,一起记录自己的所学。

若本文有错误或不足之处,请各位大佬批评指正,不吝赐教,我定当认真反思改进,谢谢!

希望各位前进的路上不迷茫,都有光明的未来。

一 单链表的基本概念

1.单链表的定义

线性表的链接表示又称单链表,它是通过一组任意的存储单元来存储线性表中的数据元素。为表示每个元素与其后继元素之间额逻辑关系,每个元素除了需要存储自身的信息外,还要存放一个指示其后继的指针。

单链表的每个节点包括两个域:数据域--存放元素本身的信息;指针域--存放其后继节点的存储位置。由于最后一个元素没有后继,它的指针不指向任何节点,称为空指针。指向链表中的第一个节点的指针称为该链表的头指针。

2.区分两个概念

头节点:为了方便操作,在单链表第一个节点之前附加一个节点,称为头节点。头节点通常不存储信息,它的指针指向单链表的第一各节点。

头指针:指向单链表中第一个节点的指针称为该链表的头指针

3.单链表的特点

优点:不要求大片连续空间,改变容量容易。

缺点:不可随机存取,要耗费一定空间存放指针。 

二 单链表的表示

typedef int ElemType;struct LinkNode {     //单链表节点类型 ElemType data;    //数据域 struct LNode* next;      //指针域 };typedef struct LinkNode PNode;//节点typedef struct LinkNode* LinkList;   //单链表类型

三 单链表的基本操作

为了操作方便,本文的所有操作均在带头节点的情况下讨论

1.单链表的初始化

LinkList InitLinkList(void){LinkList llist = (LinkList)malloc(sizeof(struct LinkNode));  //申请表头节点内存空间if (llist == NULL)//表头节点内存空间申请失败{return NULL;}llist->next = NULL;     //表头姐节点内存空间申请成功,表头节点的指针指向空return llist;}

2.单链表的创建

头插法

LinkList HeadInsertList(LinkList llist) //逆向建立单链表{PNode* s;int x;llist = (LinkList)malloc(sizeof(PNode));  //创建头节点llist->next = NULL;  //初始化空链表scanf("%d", &x);     //输入节点值while (x != 99999)   //输入99999表示结束{s = (PNode*)malloc(sizeof(PNode));    //创建新节点s->data = x;     s->next = llist->next;llist->next = s; //将新节点插入表中,llist为头节点scanf("%d", &x);}return llist;}

 尾插法

LinkList TailInsertList(LinkList llist)//正向建立单链表{ int x; //设ElemType为整型llist = (PNode*)malloc(sizeof(PNode));    //建立头节点PNode* s;     PNode* r;     //r为表尾指针scanf("%d", &x);     //输入节点的值while (x != 99999)   //输入99999表示结束,结束标志可自由选择{s = (PNode*)malloc(sizeof(PNode));s->data = x;r->next = s;     //在r节点后插入新的元素xr = s;    //r指向新的表尾节点scanf("%d", &x);}r->next = NULL;     //尾节点指针置空return llist;}

 

 3.单链表的插入

按位序插入

在表llist的第i个位置上插入指定元素e,可以把头节点看作第"0"个节点

bool InsertLinkList(LinkList* llist, int i, ElemType e){if (i < 1)    //位序不合法,报错      {return false;}int j = 0;    //当前p指向的是第几个节点,指向头节点,头节点是第0个节点PNode* p = llist;    //指针p指向当前扫描到的节点while (p != NULL && j next;j++;}if (p == NULL)      //i值不合法,报错{return false;}PNode* s = (PNode*)malloc(sizeof(PNode));   //申请新的节点内存空间if (s == NULL)//新节点内存申请失败{return false;}s->data = e;s->next = p->next;p->next = s;  //将s链接到p之后return true;}

指定节点的后插操作

在p节点之后插入元素e

bool InsertLinkListPost(LinkList llist, PNode* p, ElemType e){if (p == NULL)      //p节点不合法,报错{return false;}PNode* s = (PNode*)malloc(sizeof(PNode));  //申请新节点内存空间if (s == NULL)//新节点内存申请失败{return false;}s->data = e;s->next = p->next;p->next = s; //新节点s链接到p之后return true;}

指定节点的前插操作

在p节点之前插入元素e

法一

bool InsertLinkListPre(LinkList llist, PNode* p, ElemType e){if (p == NULL)      //p节点不合法,报错{return false;}PNode* s = (PNode*)malloc(sizeof(PNode));    //申请新节点的内存空间if (s == NULL)      //新节点内存申请失败{return false;}s->next = p->next;  p->next = s; //新节点链接到p后面s->data = p->data;  //将p中的元素复制到s中p->data = e; //用e覆盖p中的元素return true;}

法二

//在单链表中求p所指节点的前驱节点PNode LocatePreLinkNode(LinkList llist, PNode p){if (llist == NULL){return NULL;}PNode* q = llist;while (q != NULL && q->next != p)  //节点不为空且下一节点不为p{q = q->next;     //找p的前驱节点}return q;}bool InsertLinkListPost(LinkList llist, PNode* p, ElemType e){PNode* pre = LocatePreLinkNode(llist, p);if (pre == NULL)//pre为空,报错{return false;}PNode* s = (PNode*)malloc(sizeof(PNode));if (s == NULL) //新节点申请失败,报错{return false;}s->data = e;s->next = pre->next;  //将新节点连接到pre节点后面pre->next = s;return true;}

 4.单链表的删除

按位序删除

删除表llist中第i个位置上的元素,用e返回删除的元素值

bool DeleteLinkList(LinkList llist, int i, ElemType* e){if (i < 0)     //i值不合法,报错{return false;  }PNode* p = llist;     //p指向当前扫描到的节点int j = 0;     //i指向p节点是第几个节点,默认头节点是第0个节点while (p != NULL && j next;j++;}if (p == NULL) //i值不合法,报错{return false;}if (p->next == NULL)  //第i-1个节点之后已经无其它节点{return false;}PNode* q = p->next;   //q指向被删除的节点*e = q->data;  //用e返回元素的值p->next = q->next;    //将q节点从链表中断开free(q);//释放被删除节点的内存空间return true;}

指定节点的删除

删除指定节点p,用e存储删除节点的元素值

bool DeleteLinkNode(LinkList llist, PNode* p, ElemType* e){if (p == = NULL)//待删除节点不存在,报错{return false;}PNode* q = llist;while (q != NULL && q->next != p) //找p的前驱节点{q = q->next;}*e = p->data;  //e存储被删除节点p的元素值q->next = p->next;    //q指向p的下一个节点free(p);//释放p的内存空间return true;}

当待删除节点不是表尾节点时,可采用如下方法

bool DeleteLinkNode(LinkList llist, PNode* p, ElemType* e){if (p == NULL) //待删除节点不存在,报错{return false;}PNode* q = p->next;   //q指向p的后继节点*e = p->data;  //e存储被删除节点p的元素值p->data = q->data;    //用q中的元素覆盖p中的元素p->next = q->next;    //将q节点从链表中断开free(q);//释放后继节点的内存空间return true;}

指定节点后的删除

删除指定节点p后一个节点,用e存储删除节点的元素值

bool DeleteLinkNodePost(LinkList llist, PNode* p, ElemType* e){if (p == NULL) //p节点不合法,报错{return false;}PNode* q = p->next;  //q指向p的后继节点*e = q->data; //e返回待删除节点的元素值p->next = q->next;   //将q从链表中断开free(q);      //释放待删除节点的内存空间return true;}

 5.单链表的查找

按位查找

获取表llist中第i个位置的元素

PNode* GetElem(LinkList llist, int i){if (i < 0)     //i值不合法,报错{return false;}PNode* p = llist;     //指针p指向当前被扫描的节点int j = 0;     //j表示p指向的是第几个节点while (p != NULL && j next;j++;}return p;}

按值查找

在表中查找数据域==e的节点

PNode* LocateElem(LinkList llist, ElemType e){PNode* p = llist->next;//从第一个节点查找数据域为e的节点while (p != NULL && p->data != e){p = p->next;}return p;  //找到返回该节点的指针,否则返回NULL}

 6.求表长

int Length(LinkList llist){int len = 0;  //统计表长PNode* p = llist;while (p->next != NULL){p = p->next;len++;}return len;}

 

 Remember that, without your permission,

no one can make you feel inferrior.

音乐圈资讯