生活永远是自己的,美哉美哉。就像毛不易唱的二零三,给我想要的自由。
链表算告一段落,本篇是单链表的学习代码笔记,本来也想想每一步都做图,分享知识,让更多的朋友去学习,但是本人局限于能力,图片无法表达自己想要的描述,所以干脆不做图了。
随后日子会有双链表的操作,后面仍然会分享栈、队列的自学笔记,也可能写汇编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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。