链表不同于线性表,它更复杂,因为有结构体指针,也更简单,对于增删改查,更简洁。
要注意的一点,对于c语言的动态分配函数,要加入头文件 #include<stdlib.h>
一般的链表包含头指针、链尾。设置头指针是为了方便执行之后的功能,链尾一般设置为NULL,就类似遍历表的函数
void WatchLink(LinkList *head){
LinkList *p;
p=head;
while(p!=NULL) // 这行代码是为了说明链尾设置为NULL的好处
{ p=p->next; } //这行代码就是为了说明,头结点的好处
}
代码涉及到链表的建立、链表的增加、链表的删除、链表的更改、链表的查找、链表的遍历输出、链表长度的统计,我讲分开代码来讲述:
1、链表的建立:
typedef struct Link{
int data;
Link *next;
}LL;
LL *InitLink(int n){
LL *head,*node,*tail; //头节点,普通节点,尾节点
head=(LL*)malloc(sizeof(LL));//注意一定要把链表的头节点分配了空间
tail=head; //有头节点的链表
for(int i=0;i<n;i++)
{
node=(LL*)malloc(sizeof(LL)); //每个增加的节点,都要分配空间
node->data=i;
tail->next=node; //尾指针指向新节点
tail=node; //尾指针后移
}
tail->next=NULL; //尾指针要设置尾NULL
return head; //返回头指针,这就是咱们需要的链表的根本
}
2.1、链表的增加,直接插入表尾
void InsertLink(LL *head,int e){
LL *p;
p=head;
while(p->next!=NULL){ //寻找尾指针
p=p->next;
}
LL *node=(LL *)malloc(sizeof(LL)); //新增的节点,要分配空间
node->data=e; //传入要添加的数值
p->next=node; //尾指针指向了新增节点
p=node; //尾指针移动位置,移到新增的链尾
/*上面两行代码,一时半会儿可能接受不过来,但是这样想,现在有两个节点,一个旧节点,一个新增的节点,咱们不仅要让新增的节点和旧节点连接起来,还要让尾指针变位置,因为它现在不是最后的尾巴了,这两个要求也就对应着上面的两行代码
*/
p->next=NULL; //注意尾指针要指向NULL
}
2.2、链表的增加,指定位置,着就涉及到了指针的定向移动,找到了第e个节点,插入的位置是e节点后面
void insert(LL *head,int e,int a){
LL *t,*node=(LL* )malloc (sizeof(LL));
t=head;
int i=0;
while(i<e&&t!=NULL){ //找到的是第e+1个节点,插入第e+1个节点下一个位置,就像数族一样,从0(头节点)开始找,只不过,链表头节点的数据域是空的
t=t->next;
i++;
}
node->data=a;
node->next=t->next;
t->next=node;
cout<<"添加成功"<<endl;
}
3、链表的查找,我用到的是for循环,和上面增加的函数里的while差不多,也是找到第key+1个节点,传出来的是第key+1的节点的数值,但是又一个空的头节点,所以是第key个数值
int showLink(LL *L,int key){//找到第key+1个节点,也就是第key个数字
LL *p;
p=L;
for(int i=0;i<key;i++) //先变化p,后变化i: p头节点,i=0;p第二个节点时,i=1。。。。。
p=p->next;
return p->data;
}
4、链表的删除,找到的是第key+1的节点,可以把第key+2的节点删除,思路时把key+2的节点隔过去,让key+1节点下一个就是key+3节点,此过程,需要一个额外的节点转换,就像c++里面的swap函数一样
void DeleteLink(LL *L,int key){
LL *p;
p=L;
for(int i=0;i<key;i++)
p=p->next; //p变,i也变,看每次循环的结果状态,而不是看运行状态看循环里面,p是头节点时候,i是0,然后一次循环,i=1,同时p是第一个有真实数据域的节点
LL *node=(LL*)malloc(sizeof(LL)); //新增的过度节点,要分配空间
node=p->next; //此时node节点指向的是即将被删除的节点
p->next=node->next; //上面代码是为了让node->next出现,就是被删节点的下一个
/* 上面两行代码,一时半会儿可能看不懂,但你可以这样想,现在又a,b,c三个节点,为了把b删除,我们要让a直接连着c,那么我们要让a->next=c,这件事发生,所以我们需要知道c这个东西,有一个方法,就是我们可以知道b的节点地址然后让b->next就是c了,而b的节点地址可以通过a->next来获取,也就是说,a->next->next就是c了,但是这中间要有一个新的节点来过渡,就是节点d了
*/
free(node); //记得把空间的内存释放了
node=NULL; //指针空间释放了,不是指针消失了,而是它所指向的消失了,所以为了避免它乱指,给他置空
}
5、链表的修改,较简单
void ChangeLink(LL *L,int index,int key){
LL *p;
p=L;
for(int i=0;i<index;i++){
p=p->next;
} //找到的是第index+1个节点,但是第一个节点是空节点,所以,在第index个数字时,更改
p->data=key;
}
6、链表的长度统计,较简单,遍历即可
int Lonth(LL *L){
LL *p;
p=L->next; //不算头节点
int n=1; //这一个是头节点
while(p!=NULL){
n++;
p=p->next;
}
return n;
}
7、链表的输出
void PushLink(LL *List){
LL *b;
b=List;
while(b->next!=NULL){ //必须是b->next才能遍历
b=b->next; //过滤掉头节点
cout<<b->data<<endl;
}
}
8、main函数代码
int main(){
LL *tail;
LL *p=InitLink(10); //建立链表
PushLink(p); //输出所有元素
insert(p,3,999); //有顺序的尾插法,插在第3+1个节点后,插入元素为5 0 1 2 5 3
cout<<Lonth(p);
InsertLink(p,123); //尾插法
PushLink(p);
DeleteLink(p,3); //找到的是第4个节点,但第1个节点空节点,所以,删除第5个节点,也就是第4个数字,第4个数字删除
ChangeLink(p,4,99);
cout<<showLink(p,5)<<endl; //输出第5个数字
PushLink(p);
return 0;
}
9、代码缺少判空判满,后面加上
因篇幅问题不能全部显示,请点此查看更多更全内容