链表的学习
链表是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 连续的插入,删除
在结合循环语句就可以实现,多注意指针的变化。