先上函数代码
#include<iostream>
#include<cstdlib>
#include<string>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
struct node{
int data;
struct node * next;
};
typedef struct node * List;
List head=NULL;
List current=NULL,pre=NULL;
List CreateEmpty(void)
{
List Ptrl;
Ptrl=(List)malloc(sizeof(node));
return Ptrl;
}
int Length(List Ptrl){
int i=0;
while(Ptrl->next!=NULL)//算头结点不算尾节点的情况
{
i++;
Ptrl=Ptrl->next;
}
return i;
}
List Find(int i)
{
List p=head;
while(i--)//因为头结点为0,所以是--i
{
p=p->next;
}
return p;
}
List Insert(int x,int i,List Ptrl)
{
List p,s;
if(i==1)
{
s=(List) malloc(sizeof(struct node));
s->next=head;
s->data=x;
return s;//改变的是表头,所以返回不一样的表头x
}
p=Find(i-1);
if(p==NULL)
{
cout<<"参数错误,无法插入";
return NULL;
}
else
{
s=(List) malloc(sizeof(struct node));//s是新节点 p是查找到的需要被插入的节点
s->next=p->next;
p->next=s;
s->data=x;
return Ptrl;//因为是在中间插入节点,所以返回时仍是Ptrl没有改变表头
}
}
List Delete(int i,List Ptrl)//i是待删除的节点号 Ptrl是传进来的待操作的链表头
{
List s,p;
if(i==1) //头结点的情况
{
s=Ptrl;
if(Ptrl!=NULL)
Ptrl=Ptrl->next;
else
return NULL;
free(s);
return Ptrl;
}
else//中间节点的情况
{
s=Find(i-1);
p=s->next;
s->next=p->next;
free(p);
return Ptrl;
}
}
int main()
{
while(1)
{
current=CreateEmpty();//1开辟
cin>>current->data;//2赋值
if(current->data==-1) break;
if(head==NULL) //3链接
head=current;
else
pre->next=current;
current->next=NULL;//4初始
pre=current;//5存尾
}
head=Insert(110,3,head);//插入
head=Delete(3,head);//删除
current=head;
while(current!=NULL)
{
cout<<current->data<<endl;
current=current->next;
}
}
函数总结:
一、node是结构体
struct node{
int data;
struct node * next;
};
data是数据域;
二、(重)head头指针一定要在用之前赋空,否则程序会崩溃;
三(过程!!)一个链表的创建:
1、创建表头与操作指针
List head=NULL;
List current=NULL,pre=NULL;
head是表头,也就是表名;
current是操作指针,pre是暂存指针,在链接时与上一链表链接;
2、创建空节点:(创建)
List CreateEmpty(void)
{
List Ptrl;
Ptrl=(List)malloc(sizeof(node));
return Ptrl;
}
调用的时候可以用循环来获取新得到的节点:
current=CreateEmpty();//1创建
3、赋值并判断
cin>>current->data;//2赋值
if(current->data==-1) break;
创建节点后需要直接进行赋值
然后对值进行判断才可知此节点是否可以被链接
这个链表的判断是==-1时跳出,其他链表看情况进行判断
4、链接链表:(链接)
if(head==NULL) //2链接
head=current;
else
pre->next=current;
链接的本质是在操作本轮的节点时,将本节点的赋值给pre的next指针,只有头结点是将本节点直接赋给head头指针;
5、初始化next指针:(更尾)
current->next=NULL;//3更尾
这个初始化其实就是更新链表表尾,每一轮都将本轮节点的next赋NULL;
6、储存表尾
pre=current;//5存尾
储存本轮表尾,下一轮时用来链接下轮node,操作是将本轮指针赋值给pre即可;
7、结束
while(1)
{
...
if(current->data==-1) break;//6结束
}
在这里用的while(1)+if判断本轮数据域来
四:链表函数
typedef struct node* List;
1、求表长
返回值:int
参数:表头List
int Length(List Ptrl){
int i=0;
while(Ptrl->next!=NULL)//算头结点不算尾节点的情况
{
i++;
Ptrl=Ptrl->next;
}
return i;
}
一个循环从表头遍历一遍链表即可,
2、找位置
返回值:List
参数:位置i
List Find(int i)
{
List p=head;
while(i--)//因为头结点为0
{
p=p->next;
}
return p;
}
(重点!)头结点位置为0!!!
返回值是该位置的List;
3、插入值
参数:插入的值x,插入的位置,需要插入的链表头Ptrl;
返回值:已经插入好的List,用表头接收即可;
List Insert(int x,int i,List Ptrl)
{
List p,s;
if(i==1)
{
s=(List) malloc(sizeof(struct node));
s->next=head;
s->data=x;
return s;//改变的是表头,所以返回不一样的表头x
}
p=Find(i-1);
if(p==NULL)
{
cout<<"参数错误,无法插入";
return NULL;
}
else
{
s=(List) malloc(sizeof(struct node));//s是新节点 p是查找到的需要被插入的节点
s->next=p->next;
p->next=s;
s->data=x;
return Ptrl;//因为是在中间插入节点,所以返回时仍是Ptrl没有改变表头
}
}
s是新节点,p是Find(i-1);
先创建s,再对s和p进行指针操作即可;
传进的参数是第i个,插入的位置是i之后,所以这种写法是后插法,
因为表头是第0个,所以需要Find(i-1);
还有就是
s->next=p->next;
p->next=s;
这个顺序是不能改变的
1.先把前节点的next赋给新节点的next
2.新节点赋给前节点的next
4、删除节点
参数:i是传进来的位置 Ptrl是待删除的链表头
返回值:已经删除过的链表头
List Delete(int i,List Ptrl)//i是待删除的节点号 Ptrl是传进来的待操作的链表头
{
List s,p;
if(i==1) //头结点的情况
{
s=Ptrl;
if(Ptrl!=NULL)
Ptrl=Ptrl->next;
else
return NULL;
free(s);
return Ptrl;
}
else//中间节点的情况
{
s=Find(i-1);
p=s->next;
s->next=p->next;
free(p);
return Ptrl;
}
}
前 中 后
s p p->next
同样是后删法,同样需要创建s和p节点;
s=Find(i-1)
p有两个作用
一是将p->next赋值给s->next
二是记录被删除的节点,待删除后释放内存;
总结:松松散散的看了也近一个月的链表,不敢说这段时间没有懈怠,恩,走下去罢,一切都会好的
care for self
care for other