今天老师发了链表的题集,看到那个链表的题目后我发现我好像不太写了,就赶紧一点一点自己写了一遍,写了几个小时了以后终于会了一点,就赶紧来写一篇文章来巩固一下:
首先,关于链表的知识最开始的就是构建链表,那构建链表呢就是要先知道链表的结构(就是链表长啥样),比如说这样的:
struct ListNode {
int data;
struct ListNode *next;
};
我们看到这个结构其实就是以一个数字(或者是很多成员:数字,字符串等)和一个指向下一个结构(结点)的指针组成。那要在指针里面塞东西,首先就是要给它腾出一块空间来(malloc/new),然后我们就能开始构建一个链表了!
比如说写一个函数来构建链表:
void input(){
int num;//里面的数据
struct stud_node *p;//来一个指针方便后面构造结点
scanf("%d",&num);//输入数据
while(num!=0){//用0来截止
p=(struct stud_node*)malloc(sizeof(struct stud_node));//腾空间
p->num=num;//把数据塞进去
if(head==NULL) head=p;//如果是第一个数据
else tail->next=p;//如果不是第一个数据我们就接在尾巴上
tail=p;//尾巴
scanf("%d",&num);//下一个数据
}
if(head!=NULL) tail->next=NULL;/如果没有成员直接返还NULL
}
(上面就是构建一个链表的代码了,应该......挺详细的吧......)
学会了怎么构建链表后我们就可以学一下怎么去删除一个结点:
我们要要考虑两种情况:一、要删除的结点是第一个结点 二、要删除的结点不是第一个结点。为什么要分成两种情况来考虑呢,因为我们用的方法是将要删除的前一个结点连向要删除的结点的后一个结点(比如说有个链表是A->B->C,我们要删除B,就直接把A与C连接,即A->C就可以删除了)。但是如果是第一个结点,我们就不能找到他的前一个结点,所以第一个结点我们要分开来讨论:
先是头的:
while(head->data==m){//如果满足某个条件
if(head->next==NULL) return NULL;//下一个是空的的话这个删除后就啥都没了
head=head->next;//这个是要删的,所以这个不要
}
或者
while(head->data==m&&head->next) head=head->next;
然后再分析其他情况的:
while(p->next!=NULL){//下一个要存在
if(p->next->data==m){//下一个结点符合要删除的条件
struct stud_node *q=p->next;//我来存放要删除的结点
p->next=q->next;//前一个结点指向下一个结点
free(q);//释放
}else p=p->next;//没有要删除的就走向下一个
}
然后就完成删除过程了,下面献上一个类似的代码(其实就只有删除条件变了):
struct stud_node *deletelist( struct stud_node *head, int min_score ){
if(head==NULL) return NULL;
while(head->score<min_score){
if(head->next==NULL) return NULL;
head=head->next;
}
if(head==NULL) return NULL;
struct stud_node *p=head;
while(p->next!=NULL){
if(p->next->score<min_score){
struct stud_node *q=p->next;
p->next=q->next;
free(q);
}else p=p->next;
}if(head==NULL) return NULL;
return head;
}
学会构建和删除后,我们就能进行一些链表的基本操作了:
比如说逆序构建链表:
struct ListNode *createlist(){
struct ListNode *p;
struct ListNode *head=NULL;
int num;
scanf("%d",&num);
while(num!=-1){
p=(struct ListNode*)malloc(sizeof(struct ListNode));
p->data=num;//储存数据
if(head!=NULL) p->next=head;用新的结点来连接头,而不是头来连接新的结点
head=p;//新的头是新的结点
scanf("%d",&num);
}return head;
}
或者说拼接两个链表:
(题目)
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2){
struct ListNode *p=NULL;//其实就是再构建一个链表,然后把原本两个链表的值放进去
struct ListNode *head=NULL;
struct ListNode *tail=NULL;
while(list1!=NULL&&list2!=NULL){//如果两个都不为空
p=(struct ListNode*)malloc(sizeof(struct ListNode));
if(list1->data<list2->data){//选择要连接的那个链表
p->data=list1->data;
list1=list1->next;
}else{
p->data=list2->data;
list2=list2->next;
}if(head==NULL) head=p;//这就是正常的构建过程
else tail->next=p;
tail=p;
}//然后还要判断如果有一个是空的,另一个是没空时我们要做的事(就是把剩下的塞进去)
if(list1==NULL){//list1空了
while(list2!=NULL){//list2没空
p=(struct ListNode*)malloc(sizeof(struct ListNode));
p->data=list2->data;
list2=list2->next;
if(head==NULL) head=p;
else tail->next=p;
tail=p;
}
}
if(list2==NULL){//list2空了
while(list1!=NULL){//list1没空
p=(struct ListNode*)malloc(sizeof(struct ListNode));
p->data=list1->data;
list1=list1->next;
if(head==NULL) head=p;
else tail->next=p;
tail=p;
}
}
if(head==NULL) return NULL;
return head;
}
或者是我们把一个已知链表逆置:
struct ListNode *reverse( struct ListNode *head ){
struct ListNode *p;
struct ListNode *q=head;
struct ListNode *k=NULL;
while(q){
p=q;//新链表连上去
q=q->next;//原本的链表指向下一个数字
p->next=k;新链表指向上一个
k=p;//“上一个”往前走
}return p;
}
到此,我们就能成功的实现一些链表中基础中的基础的操作了!
本蒟蒻感觉链表是c语言中的一个难点,所以还特地巩固了一下,写了这篇文章,如有错误和不足请dalao们指点~
那么到这里文章就结束啦(链表里面其他的高级操作还没学,就分享不了,以后学了再来分享~)
债见!