生活永远是自己的,美哉美哉。就像毛不易唱的二零三,给我想要的自由。
链表算告一段落,本篇是单链表的学习代码笔记,本来也想想每一步都做图,分享知识,让更多的朋友去学习,但是本人局限于能力,图片无法表达自己想要的描述,所以干脆不做图了。
随后日子会有双链表的操作,后面仍然会分享栈、队列的自学笔记,也可能写汇编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); //遍历链表,返回链表长度len void 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不就解决了。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。