链表的学习
链表是C语言中的重要工具。
现在重新整理和运用。
首先是头文件。
include <stdio.h>
include <stdlib.h>
因为要申请空间,所以要用<stdlib.h>
然后就是对结构的定义。
typedef int ElementType;
typedef struct Node {
ElementType num;
struct linklist *next;
} list;
当然也可以把typedef写在外面
typedef int ElementType;
typedef struct Node list;
struct Node {
ElementType num;
struct linklist *next;
};
这里要注意的是:
typedef struct Node *list;
还是使用
typedef struct Node list;
个人而异,自己喜欢就行。
现在开始创建链表。
因为是单向链表,在进行开始的输入一般有头插法和尾插法。
如果是双向链表,也只不过在创建时要struct linklist *previous 指向上一个节点,struct link *next指向下一个节点,
当然如果是保持在动态的插入和删除,比如堆栈的运用和队列的变化,以及在实际问题中的使用。
会采用不同的方法。
下面先介绍尾插法。
首先开头
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct Node {
ElementType num;
struct Node *next;
} list;
接下来是创建函数,list* create();
我为了方便直接用的是当输入0时就结束。在运用中,可以传入一定的参数,来调整结束的条件,
反正无论是用for 循环还是while循环都是一样的。
list* create(){
list *head=NULL;
list *tail=NULL;
list *tem=NULL;
/*三个变量的初始化*/
head=(list*)malloc(sizeof(struct Node));
/*为头节点申请空间*/
head->next=NULL;
tail=head;
ElementType input=-1;
/*------创建初始化----------*/
while(1){
scanf("%d",&input);
if(input==0){
break;
}
tem=(list*)malloc(sizeof(struct Node));
tem->num=input;
tem->next=NULL;
tail->next=tem;//尾指针指向临时的指针
tail=tem;//尾指针向下一位移动
}
tem=head;//因为头指针根本没有值,下面要把它释放掉
head=head->next;//真正的头指针
free(tem);//释放开始创建的空间
return head;
}
简单来说就是。就是一直往后面加,最后重新设置一下头节点。
尾插法有个好处是,你输入的数据,在输出时时正序的。
如果你想要把整个链表头尾串联起来,只要在free(tem)前加上
tail->next=head;也就是尾又指向头。
这也是我比较喜欢尾插法。
下面时简单的输出函数和主函数。
list *print(list* head){
list *tem=head;
while(tem!=NULL){//当临时变量为NULL时结束输出
printf("%d ",tem->num);
tem=tem->next;
}
}
int main(){
list *head=NULL;
head=create();
print(head);
return 0;
}
下面介绍头插法。
同样需要临时的指针。
list* create(){
list *head;
list *tem;
head=(list*)malloc(sizeof(Node));
head->next=NULL;
ElementType input=-1;
/*------初始化-------*/
while(1){
scanf("%d",&input);
if(input==0){
break;
}
tem=(list*)malloc(sizeof(Node));
tem->next=NULL;
tem->num=input;
tem->next=head->next;//头指针的下一个是临时指针所指向的下一个
head->next=tem;//把头指针向现有的
}
/*同样头指针空间里没有数据*/
tem=head;
head=head->next;
free(tem);
return head;
}
如果使用头插法,数据会自动变成倒叙,因为插入是一直是在头节点后面插
每插入一个数,先节点指向上一个节点(头指针指向的下一个节点),然后头指针会指向这个节点。
相当于插队。
尾插法是从后面开始排队。(对应就是队列)
头插法是直接插队到第一个,后面的往后移动。(类似于堆栈,但还差的多)
-------------------不是完美的分解线
在链表中会有一系列的基本操作,长度,查找,插入,删除。
我从简单的开始。
一,
长度
求整个的链表的长度。
不想数组,链表没有固定的长度,当然可以在创建链表时,传入一定的参数,限制长度。
直接遍历整个链表,设置一个临时变量来记录。
int length(list* head){
int lon=0;
list* tem=head;
while(tem!=NULL){
lon++;
tem=tem->next;
}
return lon;
}
其实于输出链表差不多。
二,
查找。
同样,如果在链表中找一个元素,遍历就行了。
但是因为链表不能像数组那样直接找下标,二分查找就只能用树来解决。
(1)那么第一种按照序号来查找,
(2)第二种找数值,
list * findone(list* head){
list *tem=head;
ElementType a=0;
scanf("%d",&a);
while(tem->num!=a){
tem=tem->next;
}
return tem;
}
//------------
list * findtwo(list* head){
list *tem=head;
int a=0;
int i=1;
scanf("%d",&a);//链表的第一个是1不是0
while(i!=a){
i++;
tem=tem->next;
}
return tem;
}
三,
插入,删除。
为什么一起说呢,
首先,两个都是需要考虑头节点的插入,删除,
现在是两种情况,
1.单个的插入,删除。
2.连续的插入,删除。
condition one 单个的插入
传入函数需要三个,头指针,插入的数据,那个节点。
list *insert(list* head,ElementType number,int location){
//当然如果插入位置非法的
int a=length(head);
if(location>a){
return head;
}
int i=1;
list *tem=NULL;
list *node=head;
tem=(list*)malloc(sizeof(struct Node));//给新节点申请空间
if(location==1){//先判断是否是头节点
tem->num=number;
tem->next=head;//指向头节点
head=tem;//将头节点移动到开头
return head;
}else if(location!=1){
while(i!=location-1){//找到节点的前一位
node=node->next;
i++;
}
tem->next=node->next;
/*不能搞反,否则新的节点就没有下面了*/
node->next=tem;
tem->num=number;
return head;
}
}
condition two 单个的删除
删除只需要头指针和位置
list* eliminate(list *head,int location){
int i=1;
list* tem=head;
list* Node=NULL;
if(location==1){//删除头节点
head=head->next;//调整头节点位置
free(tem);
return head;
}else if(location!=1){
while(i!=location-1){//与插入一样
tem=tem->next;
i++;
}
Node=tem->next;
tem->next=Node->next;
free(Node);
return head;
}
}
这里同样可以引入非法的变量的判断,
如果对于定点的删除,只需要在寻找的加以变化
l
ist* eliminate(list *head,ElementType number){
int i=1;
list* tem=head;
list* Node=NULL;
if(head->num==number){//删除头节点
head=head->next;//调整头节点位置
free(tem);
return head;
}else {
while(tem->num!=number){//与插入一样
Node=tem;//记录上一个位置
tem=tem->next;
}
Node->next=tem->next;
free(tem);
return head;
}
}
condition three 连续的插入,删除
在结合循环语句就可以实现,多注意指针的变化。