链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域、
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。(解释和图片来自百度百科)
链表的结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域--存放结点值的数据域
next域--存放结点的直接后继的地址(位置)的
指针域(链域)
下面是实现链表的基本操作:单链表构造、插入结点,删除结点,链表倒序、正序输出:
链表的定义:
typedef int ElemType;
typedef int Status;
typedef struct LNode{ //结点类型
ElemType data;
struct LNode *next;
};
函数定义:
/*链表的构造*/
struct LNode *Create()
/*正序输出*/
void Print(struct LNode *head)
/*删除结点*/
struct LNode *Del(struct LNode *head,int num)
/*插入结点*/
struct LNode *Insert(struct LNode *head,int num,struct LNode *node)
/*链表倒序*/
struct LNode *Reverse(struct LNode *head)
单链表构造
----------------------------------------------------
struct LNode *Create()
{
struct LNode *head;
struct LNode *p1=NULL; //p1保存创建新结点的地址
struct LNode *p2=NULL; //p2保存原链表最后一个结点的地址
//p1是不断创建的,p2->next指向p1新创建结点
p1=(struct LNode*)malloc(sizeof(struct LNode));
if(p1==NULL) //结点开辟不成功
{
printf("链表创建失败!\n");
return NULL;
}else{
p2=p1; //p2指针指向的地址保留
printf("链表创建成功!\n");
head=NULL; //开始head指向NULL
printf("请开始输入数据元素且输入0作为结束标志:");
scanf("%d",&(p1->data)); //第一个首结点空间开辟可以直接读入数据
n+=1;
while(p1->data!=0){
if(n==1){
head=p1; //头结点指向第一次p1首节点
p2->next=NULL; //p2此时指向NULL,此时p2就是p1,p1->next=NULL
}else{
p2->next=p1; //用p2->next指向新开辟的p1结点;
}
p2=p1; //把p1的地址给p2保留,然后p1产生新的结点
p1=(struct LNode*)malloc(sizeof(struct LNode)); //创建新的结点
scanf("%d",&(p1->data));
n+=1; //新建立一个结点n++
}
p2->next=NULL; //链表数据存储完,单向链表最后一个结点要NULL
free(p1); //申请的空间要进行释放
p1=NULL; //释放的变量清空为NULL,否则变成野指针
return head;//返回创建链表的头部;
}
}
结点插入----------------------------------------------------
struct LNode *Insert(struct LNode *head,int num,struct LNode *node)
{
struct LNode *p1; //p1保存当前需要检查的结点地址
if(head==NULL)
{
head=node;
node->next=NULL;
n+=1;
return head;
}
p1=head;
while(p1->data!=num&&p1->next!=NULL)
{
p1=p1->next; //查看p1寻找的结点是不是所要查找到的
}//退出while()循环条件一定是找到了或者到达最后一个结点
if(p1->data==num) //找到了
{
node->next=p1->next;
p1->next=node;
n+=1;
}else{
printf("没有找到该结点\n");
}
return head;
}
结点删除 ----------------------------------------------------
struct LNode *Del(struct LNode *head,int num)
{
struct LNode *p1; //p1保存当前需要检查结点的地址
struct LNode *p2; //p2保存当前检查过结点的地址
if(head==NULL) //此时是空链表
{
printf("链表此时为空表!\n");
return head;
}else{
//定位要删除的结点
p1=head;
while(p1->data!=num&&p1->next!=NULL)
{
p2=p1; //用p2来保存当前结点的地址
p1=p1->next; //后移一个结点
}//退出while()循环条件一定是找到了或者到达最后一个结点
if(p1->data==num) //找到了的时候
{
if(p1==head){ //如果要删除的是第一个结点
head=p1->next; //头指针往后移动一个,第一个结点就不存在链表当中
}else{
p2->next=p1->next; //如果是其它结点,用原来指针指向它的下一个结点,完成删除
}
free(p1); //释放当前结点
p1=NULL;
printf("删除成功!\n");
n-=1; //结点总数减少一个
}else{
printf("表中没有该数据!\n");
}
}
return head;
}
链表倒序
----------------------------------------------------
truct LNode *Reverse(struct LNode *head)
{
struct LNode *p; //临时存储
struct LNode *p1; //存储返回结果
struct LNode *p2; //源结果结点一个一个取
p1=NULL; //开始颠倒时,已颠倒的部分为空
p2=head; //p2指向链表的头结点
while(p2!=NULL)
{
p=p2->next;
p2->next=p1;
p1=p2;
p2=p;
}
head=p1;
printf("链表倒序成功!\n");
return head;
}
正序打印
----------------------------------------------------
void Print(struct LNode *head)
{
struct LNode *p;
printf("此时链表中的数据元素有:");
p=head; //此时让p首地址和头指针首地址相同
if(head!=NULL) //只要不是空链表,就输出链表中所有的结点
{
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next; //p不断指向下一个地址
}
}
printf("\n");
}
嗯下面就是在VC上的测试:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int ElemType;
typedef int Status;
typedef struct LNode{ //结点类型
ElemType data;
struct LNode *next;
};
int n; //用来记录结点数目
struct LNode *Create()
{
struct LNode *head;
struct LNode *p1=NULL; //p1保存创建新结点的地址
struct LNode *p2=NULL; //p2保存原链表最后一个结点的地址
//p1是不断创建的,p2->next指向p1新创建结点
p1=(struct LNode*)malloc(sizeof(struct LNode));
if(p1==NULL) //结点开辟不成功
{
printf("链表创建失败!\n");
return NULL;
}else{
p2=p1; //p2指针指向的地址保留
printf("链表创建成功!\n");
head=NULL; //开始head指向NULL
printf("请开始输入数据元素且输入0作为结束标志:");
scanf("%d",&(p1->data)); //第一个首结点空间开辟可以直接读入数据
n+=1;
while(p1->data!=0){
if(n==1){
head=p1; //头结点指向第一次p1首节点
p2->next=NULL; //p2此时指向NULL,此时p2就是p1,p1->next=NULL
}else{
p2->next=p1; //用p2->next指向新开辟的p1结点;
}
p2=p1; //把p1的地址给p2保留,然后p1产生新的结点
p1=(struct LNode*)malloc(sizeof(struct LNode)); //创建新的结点
scanf("%d",&(p1->data));
n+=1; //新建立一个结点n++
}
p2->next=NULL; //链表数据存储完,单向链表最后一个结点要NULL
free(p1); //申请的空间要进行释放
p1=NULL; //释放的变量清空为NULL,否则变成野指针
return head;//返回创建链表的头部;
}
}
void Print(struct LNode *head)
{
struct LNode *p;
printf("此时链表中的数据元素有:");
p=head; //此时让p首地址和头指针首地址相同
if(head!=NULL) //只要不是空链表,就输出链表中所有的结点
{
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next; //p不断指向下一个地址
}
}
printf("\n");
}
struct LNode *Del(struct LNode *head,int num)
{
struct LNode *p1; //p1保存当前需要检查结点的地址
struct LNode *p2; //p2保存当前检查过结点的地址
if(head==NULL) //此时是空链表
{
printf("链表此时为空表!\n");
return head;
}else{
//定位要删除的结点
p1=head;
while(p1->data!=num&&p1->next!=NULL)
{
p2=p1; //用p2来保存当前结点的地址
p1=p1->next; //后移一个结点
}//退出while()循环条件一定是找到了或者到达最后一个结点
if(p1->data==num) //找到了的时候
{
if(p1==head){ //如果要删除的是第一个结点
head=p1->next; //头指针往后移动一个,第一个结点就不存在链表当中
}else{
p2->next=p1->next; //如果是其它结点,用原来指针指向它的下一个结点,完成删除
}
free(p1); //释放当前结点
p1=NULL;
printf("删除成功!\n");
n-=1; //结点总数减少一个
}else{
printf("表中没有该数据!\n");
}
}
return head;
}
struct LNode *Insert(struct LNode *head,int num,struct LNode *node)
{
struct LNode *p1; //p1保存当前需要检查的结点地址
if(head==NULL)
{
head=node;
node->next=NULL;
n+=1;
return head;
}
p1=head;
while(p1->data!=num&&p1->next!=NULL)
{
p1=p1->next; //查看p1寻找的结点是不是所要查找到的
}//退出while()循环条件一定是找到了或者到达最后一个结点
if(p1->data==num) //找到了
{
node->next=p1->next;
p1->next=node;
n+=1;
}else{
printf("没有找到该结点\n");
}
return head;
}
struct LNode *Reverse(struct LNode *head)
{
struct LNode *p; //临时存储
struct LNode *p1; //存储返回结果
struct LNode *p2; //源结果结点一个一个取
p1=NULL; //开始颠倒时,已颠倒的部分为空
p2=head; //p2指向链表的头结点
while(p2!=NULL)
{
p=p2->next;
p2->next=p1;
p1=p2;
p2=p;
}
head=p1;
printf("链表倒序成功!\n");
return head;
}
int main()
{
int ch;
int num;
struct LNode *Head;
struct LNode *Node;
printf("********************\n");
printf("1、插入结点\n2、删除结点\n3、链表倒序\n4、正序输出\n5、退出程序\n");
printf("********************\n");
Head=Create();
printf("请输入接下来进行的步骤:");
while(scanf("%d",&ch)&&ch!=0)
{
if(ch==1){//Insert()
Node=(struct LNode*)malloc(sizeof(struct LNode));
printf("输入要插入数据:");
scanf("%d",&Node->data);
printf("输入要插入结点的后面位置:");
scanf("%d",&num);
Head = Insert(Head,num,Node);
}
if(ch==2){//Del()
printf("输入要删除的数据:");
scanf("%d",&num);
Head = Del(Head,num);
}
if(ch==3){//Reverse()
Head = Reverse(Head);
}
if(ch==4){
Print(Head);
}
printf("请输入接下来进行的步骤:");
}
printf("程序退出成功!\n");
return 0;
}