单链表(包含反转、导出、循环链表思路)
生活永远是自己的,美哉美哉。就像毛不易唱的二零三,给我想要的自由。
链表算告一段落,本篇是单链表的学习代码笔记,本来也想想每一步都做图,分享知识,让更多的朋友去学习,但是本人局限于能力,图片无法表达自己想要的描述,所以干脆不做图了。
随后日子会有双链表的操作,后面仍然会分享栈、队列的自学笔记,也可能写汇编8086的心得,希望大家一起共勉。
代码可能有些繁琐(很多地方都可以优化),只是新手 给 新手的一些参考
反转链表用的迭代思路参考(引用):https://blog.csdn.net/blioo/article/details/62050967
作者:blioo
本人感觉引用文章思路非常好,适合初学者,推荐给大家,下面贴自己的学习心得:
#include <stdio.h>#include <malloc.h>#include <stdlib.h>typedef struct Node{ int data; struct Node *next;}Node,*PNode;PNode ControlLinkList(PNode PHead, int len); //控制函数PNode CreateLinkList(void); //构造链表int TraverseLinkList(PNode PHead); //遍历链表,返回链表长度lenvoid GetInfo(PNode PNew, int i); //用户信息输入,当输入代码量大的时候封装起来void InsertLinkList(PNode PHead, int pos, int data, int len); //插入某节点void FindLinkList(PNode PHead, int pos); //寻找某节点void DeleteLinkList(PNode PHead, int pos); //删除某节点void ModifyLinkList(PNode PHead, int pos, int data); //修改某数据void ExportLinkList(PNode PHead); //导出链表(或导出某节点之前、之后的数据稍加修改即可)PNode ReverseLinkList(PNode PHead); //逆转链表void ReleaseLinkList(PNode PHead); //释放链表int main(void){ PNode PHead = CreateLinkList(); int len = TraverseLinkList(PHead); ControlLinkList(PHead,len); return 0;}PNode ControlLinkList(PNode PHead, int len){ int pos; int data = 0; printf("请输入插入的节点pos:\n"); scanf("%d",&pos); printf("请输入插入的数据data:\n"); scanf("%d",&data); InsertLinkList(PHead, pos, data, len); TraverseLinkList(PHead); printf("请输入查询的节点: "); scanf("%d",&pos); FindLinkList(PHead, pos); printf("请输入删除的节点: "); scanf("%d",&pos); DeleteLinkList(PHead, pos); TraverseLinkList(PHead); printf("请输入修改的节点: "); scanf("%d",&pos); printf("请输入修改的数据: "); scanf("%d",&data); ModifyLinkList(PHead, pos, data); TraverseLinkList(PHead); ReverseLinkList(PHead); TraverseLinkList(PHead); ReleaseLinkList(PHead); return PHead;}void GetInfo(PNode PNew, int i){ printf("请输入 No.%d Data = ",i+1); scanf("%d",&PNew->data);}PNode CreateLinkList(void){ int i; int len = 0; PNode PHead = (PNode)malloc(sizeof(Node)); PNode PTail = PHead; if( NULL == PHead ) { printf("内存分配失败\n"); exit(EXIT_FAILURE); } PTail->next = NULL; printf("请输入节点个数: "); scanf("%d",&len); for( i = 0; i < len; i++ ) { PNode PNew = (PNode)malloc(sizeof(Node)); if( NULL == PNew ) { printf("内存分配失败\n"); exit(EXIT_FAILURE); } GetInfo(PNew, i); PTail->next = PNew; PNew->next = NULL; PTail = PNew; } printf("共%d个链表创建成功\n",i+1); return PHead;}int TraverseLinkList(PNode PHead){ int len = 0; PNode p = PHead->next; while( NULL != p) { len++; printf("No.%d Data = %d\n",len,p->data); p = p->next; } printf("遍历完成\n"); return len;}void InsertLinkList(PNode PHead, int pos, int data, int len) { int i = 0; PNode p = PHead->next; if( NULL != p ) { PNode PNew = (PNode)malloc(sizeof(Node)); if( NULL == PNew ) { printf("分配内存失败"); exit(EXIT_FAILURE); }// printf("LEN = %d\n",len); if( 0 != pos-1 ) { int l = 1; //为了弥补i从0开始 while( l < pos-1 ) //中间插法 { l++; p = p->next; } PNew->data = data; PNew->next = p->next; p->next = PNew; } /* else if( pos > len && 0 != pos-1 ) //插入链表尾 { while( i < len ) { i++; p = p->next; } p->next = PNew; //最后一个p节点指向NULL PNew->data = data; PNew->next = NULL; } */ else { PHead->next = PNew; //插入链表头 PNew->data = data; PNew->next = p; } } else { printf("空链表\n"); }}void FindLinkList(PNode PHead, int pos){ int i = 0; PNode p = PHead->next; if( NULL != p ) { while( i < pos-1 ) { i++; p = p->next; } printf("查找元素成功,数据如下:\n"); printf("No.%d Data = %d\n",i+1,p->data); } else { printf("链表为空\n"); }} void DeleteLinkList(PNode PHead, int pos){ int i = 0; PNode p = PHead->next; PNode PTemp; while( NULL != p && i != (pos-1) ) { i++; p = p->next; } PTemp = p->next; p->next = p->next->next; free(PTemp); PTemp = NULL; printf("删除节点成功\n");}void ModifyLinkList(PNode PHead, int pos, int data){ int i = 0; PNode p = PHead->next; while( NULL != p && i != pos-1 ) //一般用这种方式来判空与循环代码简洁 { i++; p = p->next; } p->data = data; printf("修改数据成功:\n"); printf("No.%d Data = %d\n\n",i,p->data);}void ExportLinkList(PNode PHead){ FILE *fp; PNode p = PHead->next; if( (fp = fopen("LinkList.txt","ab")) == NULL ) { printf("读取文件失败,创建文件成功"); exit(EXIT_FAILURE); } while( NULL != p ) { fputc(p->data,fp); p = p->next; } printf("导出成功"); fclose(fp);}PNode ReverseLinkList(PNode PHead){ PNode q = NULL; //作为反转节点 PNode Ptemp = NULL; //建立新节点指向下一个 PNode p = PHead->next; //指向第一个链表数据 PHead->next = NULL; //头结点为空 while( NULL != p ) { Ptemp = p->next; //下一个节点 p->next = q; //指向反转节点 q = p; //q指向前一个节点p q->next = p; p = Ptemp; //p接着去下一个节点 } PHead->next = q; //头结点指向翻转后的链表 printf("链表翻转成功\n"); return PHead;}void ReleaseLinkList(PNode PHead){ PNode p = PHead->next; PNode temp; PHead->next = NULL; free(PHead); while( NULL != p ) { temp = p->next; free(p); p = temp; } free(temp); printf("释放成功!\n");}
代码在window7 64 VC++6.0编译通过粘贴,代码可能缩进有些不好看。下面说一说循环单链表思路,姑且以我的认识和实际的应用,就是就体现在循环的不同。
1、在创建单链表的时候,最后把PNew->next = NULL 改为 PNew->next = PHead;
2、这里PHead是头结构体指针,所以->next才是指向第一个数据。
3、循环单链表,PHead可以从链表任意节点开始遍历都可以遍历整个链表。
注意:循环条件不可以是while( NULL !=p ),因为循环链表没有NULL值,进入死循环了就。头尾相连,遍历条件应该改为 while( PHead != p ),头不等于p不就解决了。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。