链表编程实战(一):单链表

来源:互联网 发布:linux 修改时区 编辑:程序博客网 时间:2024/06/10 21:09
笔者这几天都在学习链表知识,分别进行了单链表编程和双链表编程。本文仅用于笔者个人学习,如读者想具体了解链表,请参考其他作者。本文内容为本人单链表编程代码,下一篇文章为双链表编程。
ps:本文函数名使用中文拼音命名,仅用于方便个人学习,实际项目编程中请勿使用拼音命名方法。
链表编程学习:单链表
#include  < stdio.h>
#include  < string.h>
#include  < stdlib.h>
更正说明:现在才发现博客会屏蔽一些字符,会让我以前文章里的代码的头文件<>显示不出来,现说明更正;刚测试发现的解决方法,在头文件名前面加入空格,例如<stdio.h>,即可正常显示。
PS:为方便阅读,下面深黑色字体为函数定义
//void bzero(void *s, size_t n);
//void *memset(void *s, int c, size_t n);
//void *malloc(size_t size);
// void free(void *ptr);

struct node  //定义链表节点
{
int num;
struct node *pNext;
};

struct node * create_node(int num)//创建新节点
{
struct node *p =(struct node *)malloc(sizeof(structnode));
//检查是否分配成功
if(NULL==p)
{
printf("malloc error\n");
return NULL;
}
//清理申请到的堆内存(去掉也可以运行,不过不好)
bzero(p,sizeof(struct node));
//填充节点
p->num = num;
p->pNext = NULL;
//将本节点和头指针关联起来后返回节点
return p;
}

void insert_tail(struct node *pHeader,struct node*new)//尾部插入函数
{
//第一步:找到最后一个节点;
//第二步:将新节点插入最后一个节点尾部
int cnt=0;  //用来统计节点数目
struct node *p =pHeader;
while(NULL != p->pNext)
{
p=  p->pNext; //往后走一个节点
cnt++;
}
p->pNext = new;
pHeader->num = cnt +1;//将节点数目保存到头节点有效数据中
}

void insert_head(struct node *pHeader, struct node*new)//头部插入函数
{
//1、新节点的pNext指向原来的第一个节点(不是头节点)
new->pNext = pHeader->pNext;
//2、头节点的pNext指向新节点的地址
pHeader->pNext = new;
//3、头节点计数+1
pHeader->num +=1; 将节点数目保存到头节点有效数据中
}

void bianli(struct node *pHeader)//遍历函数
{
struct node *p=pHeader;
printf("******Start bianli******\n");
while(NULL !=p->pNext)
{
p=p->pNext;  //循环增量,跳过头节点数目统计的打印
printf("node num:%d\n",p->num);
}
printf("*******The End*******\n");
}

//返回值:找到节点并删除则返回0;未找到返回-1
int delete_node(struct node *pHeader,int num)  //删除节点函数
{
struct node *p=pHeader;//下面用来指向当前节点
struct node *p1=NULL;//用来指向当前节点的前一个节点
while(NULL !=p->pNext)
{
p1 = p;//在走向下一个节点前保存当前节点地址,在删除尾节点时使用
p=p->pNext;  //循环增量,跳过头节点数目统计的打印
if(p->num == num)
{
//找到节点后处理
//分两种情况:1、要找的是尾节点;2、不是尾节点
if(NULL==p->pNext)
{
//尾节点
//难点:需建立新指针指向前一个节点,该节点保存后一个节点的地址,让它设为NULL就相当于删除尾节点了
p1->pNext = NULL;
free(p);
}
else
{
//普通节点
p1->pNext = p->pNext; //将要删除节点的前一个节点和它的后一个节点前后相接
free(p);
}
//处理完后退出程序
return 0;
}
}
printf("Not Finding\n");
return -1;
}

void nixu(struct node *pHeader)//逆序:遍历+头插入
{
struct node *p=pHeader->pNext;//pHeader指向头节点,p指向第一个有效节点
//当链表没有有效节点或者只有一个节点时,逆序不做任何操作
struct node *pback;
if((NULL==p||NULL==p->pNext))
return;
//当链表有2个或2个以上节点时,逆序开始操作
while(NULL!=p->pNext)//判断是否为尾节点
{
pback = p->pNext;
if(p == pHeader->pNext)
{
//第一个有效节点
p->pNext=NULL;
}
else
{
//头部插入一个节点后,和后面节点相接
p->pNext=pHeader->pNext;
}
pHeader->pNext=p;
p= pback;
}
//下面补救最后一个节点:4.......有点牵强,哈哈
insert_head(pHeader,p);
}

int main ()
{
//应用4、使用头节点,数据中存节点数目
struct node *pHeader =create_node(0);//头指针用来指向头节点,头节点用于存节点数目
insert_tail(pHeader,create_node(1));
insert_tail(pHeader,create_node(2));
insert_tail(pHeader,create_node(3));
insert_tail(pHeader,create_node(4));
printf("Header node num:%d\n",pHeader->num);
bianli(pHeader);//调用遍历
nixu(pHeader);//逆序函数
printf("******After nixu******\n");
bianli(pHeader);
 
/ *
//注意:下面代码模块测试,请分别进行。
 
测试3、调用删除节点函数
 delete_node(pHeader,2);
 printf("******After delete******\n");
 bianli(pHeader);
  
测试2、尾插入节点,也可调用头部插入节点函数
struct node *pHeader =create_node(0);//头指针用来指向头节点,头节点用于存节点数目
 insert_tail(pHeader,create_node(1));
 insert_tail(pHeader,create_node(2));
 insert_tail(pHeader,create_node(3));
  bianli(pHeader);

测试1、此步骤是初步学习的编程。本模块只使用头指针,不使用头节点
 struct node *pHeader = NULL;
 pHeader = create_node(1); 
 pHeader->pNext =create_node(2);  
 pHeader->pNext->pNext =create_node(3);    
 printf("pHeader -> num =%d\n",pHeader->num);
 printf("pHeader ->pNext -> num =%d\n",pHeader->pNext->num);
 printf("pHeader ->pNext->pNext->num =%d\n",pHeader->pNext->pNext->num);
 printf("pHeader->pNext->pNext->pNext->num =%d\n",pHeader->pNext->pNext->pNext->num);
* /
}
 
0 0