写给初学者的数据结构——初识链表(带头结点)(标准C实现)
2019-07-12 16:11
281 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43796828/article/details/95616496
全文一共3195字,理解部分大约需要15分钟的阅读时间,感谢遇见!
目录
1、相关文章
C++(理解篇):https://www.geek-share.com/detail/2773834387.html(推荐优先阅读)
Java:https://blog.csdn.net/weixin_43796828/article/details/95611547
2、理解:
C实现与C++实现的区别在于:C++采用了引用调用的参数传递方式,而标准C不支持。
高一凡《数据结构》中,有这样一段话。
所以,将C++函数中形参表中以&打头的参数改成以*打头的参数,再将函数中该参数前加*即可。另外,调用该函数,实参前应加&。
3、示例:
[code]Status CreatDescend(LinkList &L,int n) { //按非升序建立n个元素的线性表 int j; LinkList p,q,s; if(n<=0) { return ERROR; } InitList(L); printf("请输入%d个元素:\n",n); s = (LinkList)malloc(sizeof(struct LNode)); //第一个结点 scanf("%d",&s->data); s->next = NULL; L->next = s; for(j=1; j<n; j++) { s = (LinkList)malloc(sizeof(struct LNode)); //其余节点 scanf("%d",&s->data); q = L; p = L->next; while(p&&p->data>s->data) { q = p; p = p->next; //指针后移 } s->next = q->next; //元素插在q的后面 q->next = s; } return OK; }
[code]CreatAscend(L,n);
[code]Status CreatAscend(LinkList *L,int n) { //按非降序建立n个元素的线性表 int j; LinkList p,q,s; if(n<=0) { return ERROR; } InitList(*L); printf("请输入%d个元素:\n",n); s = (LinkList)malloc(sizeof(struct LNode)); //第一个结点 scanf("%d",&s->data); s->next = NULL; (*L)->next = s; for(j=1; j<n; j++) { s = (LinkList)malloc(sizeof(struct LNode)); //其余结点 scanf("%d",&s->data); q = *L; p = (*L)->next; while(p && p->data<s->data) { q = p; p = p->next; //指针后移 } s->next = q->next; //元素插在q的后面 q->next = s; } return OK; }
[code]CreatAscend(&L,n);
其中,再调用两程序中,实参L的类型是相同的。还有,在转换过程中,遇到&*或*&可“抵消”,即将*&T转换为T。
我的理解:将实参(地址)传递给一个二维指针,函数中用这个参数,前面加一个*号,意味着调用二维指针所指向的内容,也就是一维指针。&*可以相互抵消,但是我们都看到了,C程序里调用L的时候前面都加了*号。也就是说,&*可以相互抵消,但是原来的参数调用方式可能会有所改变。
4、完整测试源码:
[code]#include<stdio.h> #include<math.h> //储存着OVERFLOW,值为3 #include<stdlib.h> typedef int ElemType; typedef int Status; typedef int Boolean; #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 struct LNode { ElemType data; struct LNode *next; }; typedef struct LNode* LinkList; Status InitList(LinkList *L) //操作结果: 构造一个空的线性表L { (*L) = (LinkList)malloc(sizeof(struct LNode)); //产生头结点,并使L指向此头结点 if(!(*L)) //存储分配失败 { exit(OVERFLOW); } (*L)->next = NULL; return OK; } Status ListInsert(LinkList L,int i,ElemType e) //在带头节点的单链线性表L中第i个位置之前插入元素e { int j = 0; LinkList p = L,s; while(p && j<i-1) //寻找第i-1个结点,令p指向它。p指向第一个结点的时候,j为1. { p = p->next; j++; }//这里有两个终止条件,一个是链表遍历完了,一个是找到了 if(!p || j>i-1) //如果遍历完了没找到 { return ERROR; } s = (LinkList)malloc(sizeof(struct LNode)); //生成新节点 s->data = e; //插入L中 s->next = p->next; p->next = s; return OK; } Status ListDelete(LinkList L,int i,ElemType *e) //在头结点的单链线性表l中,删除第i个元素,并由e返回其值 { int j=0; LinkList p=L,q; while(p->next && j<i-1) //寻找第i个结点,并令p指向其前趋,即第i-1个结点。p指向第一个结点的时候,j为1. { p = p->next; j++; }//与ListInsert对比一下?只有while里面的p->next不同 if(!p->next || j>i-1) //删除位置不合理 { return ERROR; } q = p->next; //删除并释放节点 p->next = q->next; *e = q->data; free(q); return OK; } Status DeleteElem(LinkList L,ElemType e) { //删除表中值为e的元素,并返回TRUE;如无次元素,则返回FALSE LinkList p = L, q; while(p) { q = p->next; if(q && q->data==e) { p->next = q->next; free(q); return TRUE; } p = q; } return FALSE; } int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType)) { //初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) //操作结果: 返回L中第1个与e满足关系compare()的数据元素的位序. // 若这样的元素不存在,则返回值为0 int i = 0; LinkList p = L->next; while(p) { i++; if(compare(p->data,e)) //找到这样的数据元素 { return i; } p = p->next; } return 0; } Status comp(ElemType c1,ElemType c2) { //数据元素判定函数(相等为TRUE,否则为FALSE) if(c1==c2) { return TRUE; } else { return FALSE; } } Status ReplaceElem(LinkList L,int i,ElemType e) //用e取代表l中第i个元素的值 { LinkList p = L; int j = 0; while(p->next && j<i) //j为1的时候p指向第一个结点 { j++; p = p->next; }//这里有两个终止条件,一个是p指向空,即链表遍历完毕。另一个是j==i,即找到对应元素。 if(j==i) { p->data = e; return OK; } else //表中不存在第i个元素 { return ERROR; } } Status DestoryList(LinkList *L) { //初始条件: 线性表L已存在。 //操作结果: 销毁线性表L LinkList p = *L; while(p) { p = (*L)->next; free(*L); (*L) = p; } return OK; } Status ClearList(LinkList L) { //初始条件: 线性表L已存在. //操作结果: 将L重置为空表 LinkList p,q; p = L->next; //p指向第一个结点 while(p) //没到表尾 { q = p->next; free(p); p = q; } L->next = NULL; return OK; } Status ListEmpty(LinkList L) { //初始条件:线性表L已存在。 //操作结果:若为空表,则返回FAlSE; if(L->next) //非空 { return FALSE; }else { return TRUE; } } int ListLength(LinkList L) { //初始条件: 线性表L已存在。 //操作结果: 返回L中数据元素的个数 int i = 0; LinkList p = L->next; //p指向第一个结点 while(p) //没到表尾 { i++; p = p->next; } return i; } Status GetElem(LinkList L,int i,ElemType *e) { //L为带头结点的单链表的头指针 //当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR int j = 1; //j为计数器 LinkList p = L->next ; //p指向第一个结点 while(p && j<i)//p指向第2个结点时,j为2。所以j为i时,p指向第i个结点 { p = p->next; j++; } if(!p || j>i) //第i个元素不存在 { return ERROR; } *e = p->data; //取第i个元素 return OK; } Status GetFirstElem(LinkList L,ElemType *e)//返回表头元素的值 { LinkList p = L->next; if(!p) { return ERROR; } else { *e = p->data; } return OK; } Status PriorElem(LinkList L,ElemType cur_e,ElemType *pre_e) { //初始条件: 线性表L已存在 //操作结果: 若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱。 // 返回OK;否则操作失败,pre_e无定义,返回INFEASIBLE LinkList q,p = L->next; //p指向第一个结点 while(p->next) //p所指结点有后继 { q = p->next; //q为p的后继,实质是从第二个判到最后一个 if(q->data==cur_e) { *pre_e = p->data; return OK; } p = q; } return INFEASIBLE; } Status NextElem(LinkList L,ElemType cur_e,ElemType *next_e) { //初始条件:线性表L已存在 //操作结果: 若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继 // 返回OK;否则操作失败,next_e无定义,返回INFEASIBLE LinkList p = L->next; //p指向第一个结点 while(p->next) //p所指结点有后继 { if(p->data==cur_e) //实质是从第一个判到倒数第二个 { *next_e = p->next->data; return OK; } p = p->next; } return INFEASIBLE; } void visit(ElemType c) { printf("%d ",c); } Status ListTraverse(LinkList L,void(*vi)(ElemType)) { //初始条件: 线性表L已存在 //操作结果: 依次对L的每个数据元素调用函数vi().一旦vi()失败,则操作失败 LinkList p = L->next; while(p) { vi(p->data); p = p->next; } printf("\n"); return OK; } Status HeadInsert(LinkList L,ElemType e) { //初始条件:线性表L已存在。 //操作结果: 在L的头部插入新的数据元素e,作为链表的第一个元素 LinkList s; s= (LinkList)malloc(sizeof(struct LNode)); //生成新结点 s->data = e; //给结点赋值 s->next = L->next; //插在表头 L->next = s; return OK; } Status EndInsert(LinkList L,ElemType e) { //初始条件:线性表L已存在. //操作结果:在L的尾部插入新的数据元素e,作为链表的最后一个元素 LinkList p = L; while(p->next) //使p指向表尾元素 { p = p->next; } p->next = (LinkList)malloc(sizeof(struct LNode)); //在表尾生成新节点 p->next->data = e; //给新节点赋值 p->next->next = NULL; //表尾 return OK; } Status DeleteFirst(LinkList L,ElemType *e) { //初始条件: 线性表L已存在,且有不少于1个元素 //操作结果: 删除L的第一个数据元素,并由e返回其值 LinkList p=L->next; if(p) { *e = p->data; L->next = p->next; free(p); return OK; } else { return ERROR; } } Status DeleteTail(LinkList L,ElemType *e) { //初始条件: 线性表L已存在,且有不少于1个元素 //操作结构: 删除L的最后一个数据元素,并用e返回其值 LinkList p=L,q; if(!p->next) //链表为空 { return ERROR; } while(p->next) { q = p; p = p->next; } q->next = NULL; //新尾结点的next域设为NULL *e = p->data; free(p); return OK; } void InsertAscend(LinkList L,ElemType e) { //初始条件: 按非降序排列的线性表L已存在。 //操作结果: 在L中按非降序插入新的数据元素e LinkList q=L,p=L->next; while(p&&e>p->data) { q = p; p = p->next; } q->next = (LinkList)malloc(sizeof(struct LNode)); //插在q后 q->next->data = e; q->next->next = p; } void InsertDescend(LinkList L,ElemType e) { //初始条件:按非升序排列的线性表L已存在. //操作结果:在L中按非升序插入新的数据元素e LinkList q = L,p = L->next; while(p && e<p->data) { q = p; p = p->next; } q->next = (LinkList)malloc(sizeof(struct LNode)); //插在q后 q->next->data = e; q->next->next = p; } Status CreatAscend(LinkList *L,int n) { //按非降序建立n个元素的线性表 int j; LinkList p,q,s; if(n<=0) { return ERROR; } InitList(&(*L)); printf("请输入%d个元素:\n",n); s = (LinkList)malloc(sizeof(struct LNode)); //第一个结点 scanf("%d",&s->data); s->next = NULL; (*L)->next = s; for(j=1; j<n; j++) { s = (LinkList)malloc(sizeof(struct LNode)); //其余结点 scanf("%d",&s->data); q = *L; p = (*L)->next; while(p && p->data<s->data) { q = p; p = p->next; //指针后移 } s->next = q->next; //元素插在q的后面 q->next = s; } return OK; } Status CreatDescend(LinkList *L,int n) { //按非升序建立n个元素的线性表 int j; LinkList p,q,s; if(n<=0) { return ERROR; } InitList(&(*L)); printf("请输入%d个元素:\n",n); s = (LinkList)malloc(sizeof(struct LNode)); //第一个结点 scanf("%d",&s->data); s->next = NULL; (*L)->next = s; for(j=1; j<n; j++) { s = (LinkList)malloc(sizeof(struct LNode)); //其余节点 scanf("%d",&s->data); q = *L; p = (*L)->next; while(p&&p->data>s->data) { q = p; p = p->next; //指针后移 } s->next = q->next; //元素插在q的后面 q->next = s; } return OK; } int main() { LinkList L; ElemType d,e; Status i; int n; printf("按非降序建立n个元素的线性表L,请输入元素个数n: "); scanf("%d",&n); CreatAscend(&L,n); printf("依次输出L的元素: "); ListTraverse(L,visit); //按非降序插入元素10 InsertAscend(L,10); printf("按非降序插入元素10后,线性表L为: "); ListTraverse(L,visit); HeadInsert(L,12); //在L的头部插入12 EndInsert(L,9); //在L的尾部插入9 printf("在L头部插入12,尾部插入9后,线性表L为: "); ListTraverse(L,visit); i = GetFirstElem(L,&e); //此句加 printf("第1个元素是:%d\n",e); //此句加 printf("请输入要删除的元素的值: "); scanf("%d",&e); i = DeleteElem(L,e); if(i) { printf("成功删除%d!\n",e); } else { printf("不存在元素%d!\n",e); } printf("线性表L为:"); ListTraverse(L,visit); printf("请输入要取代的元素的序号 元素的新值: "); scanf("%d %d",&n,&e); ReplaceElem(L,n,e); printf("线性表L为:"); ListTraverse(L,visit); DestoryList(&L); printf("销毁L后,按非升序重新建立n个元素的线性表L,请输入元素的个数n(n>2): "); scanf("%d",&n); CreatDescend(&L,n); printf("依次输出L的元素: "); ListTraverse(L,visit); InsertDescend(L,10); //按非升序插入元素10 printf("按非升序插入元素10后,线性表L为: "); ListTraverse(L,visit); printf("请输入要删除的元素的值: "); scanf("%d",&e); i = DeleteElem(L,e); if(i) { printf("成功删除%d!\n",e); } else { printf("不存在元素%d\n",e); } printf("线性表L为: "); ListTraverse(L,visit); DeleteFirst(L,&e); DeleteTail(L,&d); printf("删除表头元素%d和表尾元素%d后,线性表L为: ",e,d); ListTraverse(L,visit); return 0; }
5、运行截图:
再次感谢您的阅读!谢谢你!
相关文章推荐
- 写给初学者的数据结构——初识链表(带头结点)(C++实现)
- 数据结构(四)——单链表 、带头结点的单链表、循环链表 及其实现
- 数据结构 带头结点的单链表 操作大全 最全的链表操作(c++实现)
- 用C++实现数据结构二 带头结点的单链表
- 经典算法与数据结构的c++实现——带头结点的单链表
- 数据结构-java与c实现带头结点的单链表
- 数据结构 P38 算法实现 在带头结点的单链表的第i个元素插入元素e
- 数据结构(四)——单链表 、带头结点的单链表、循环链表 及其实现
- 数据结构模版----单链表SimpleLinkList[不带头结点&&伪OO](C语言实现)
- 数据结构(二)——单链表 、带头结点的单链表、循环链表 及其实现
- 带头结点的单链表——数据结构课堂作业
- 【c++版数据结构】之单链表的实现(带头结点以及尾节点)
- 【c++版数据结构】之循环单链表的实现(带头结点以及尾节点)
- 带头结点的链表头插法C++实现
- C实现头插法和尾插法来构建单链表(带头结点)
- 线性表——带头结点单链表的实现
- c语言实现--不带头结点的单链表操作
- 试编写在无头结点的单链表上实现线性表的插入操作的算法,并和带头结点的单链表上的插入操作的算法进行比较
- 约瑟夫环问题(不带头结点单循环链表实现和数组实现)
- 数据结构:带头结点的双向循环链表