什么是链表
链表是数据结构中常见的一种存储结构,他是非顺序的。其中的数据元素的逻辑孙旭是靠着链表中的指针地址来进行实现。
链表的定义
typedef struct Node {
Elemtype data;//数据域
Node* next;//指针域
}Node,*LinkList;
链表中一个Node代表了一个节点。其中又有头节点和首元节点。
首元节点就是存储数据的第一个节点,即为首元节点。
头节点实在首元节点之前所设立的节点,头节点的指针域指向的就是首元节点。头节点的数据域是可以不存储数据信息的,也可以存储一些链表的信息,比如说,链表长度。
链表的初始化
LinkList InitList( ){
Node *list;
list=(Node*) malloc(sizeof(Node));//给节点分配内存
if(list==NULL){
printf("申请空间失败");
exit(0);
}//如果在内存空间没申请到内存,还是报错的好,不然会出现意想不到的事情
list->next=NULL;
return list;
}
头插法
头插法即从头部开始插入,每一个新插入的节点都会从头开始插入。通过每插入一个节点把新节点的指针域指向之前插入的节点的地址从而达到链的效果。
/**头插法*/
LinkList LinkListHead(){
// printf("头插法插入");
Node* list;
list=(Node*) malloc(sizeof(Node));
list->next=NULL;
int x;
while (scanf("%d",&x)!=EOF){
Node* p;
p=(Node *) malloc(sizeof(Node));
p->data=x;
p->next=list->next;
list->next=p;
// printf("插入成功\n");
}
return list;
}
在此之中最核心的两行代码为:
p->next=list->next;//获取list所存地址进行指向原本的节点
list->next=p;//list在重新指向新的节点
尾插法
头插法虽然可以插入,但是当我们对链表进行遍历输出的时候,往往会发现输出的顺序会是跟我们输入的顺序相反。而尾插法就可以实现输入输出一致。
LinkList LinkListT(){
// printf("尾插法");
Node *list,*r;
list->next=NULL;
r=list;
int x;
while (scanf("%d",&x)!=EOF){
Node *p;
p=(Node *) malloc(sizeof(Node));
p->data=x;
r->next=p;
r=p;
}
r->next=NULL;
return list;
}
对于尾插法来说,最核心的步骤为:
r->next=p;//指针域指向新的节点的地址
r=p;//向前移一步。
链表的插入
链表的插入则是对链表所指定的的位置进行插入,要想实现链表的插入,则需要重新定义2个节点。只有通过新的节点接收前驱指针域的地址,在前驱的指针域指向新插入的节点,才能实现链表的插入。
LinkList List_Insert(LinkList List,int i,int x){
Node *p,*pre;
p=(Node*) malloc(sizeof (Node));
p->data=x;
pre=List;
int j=1;
for (j = 1; j < i; j++) {
pre = pre->next;//通过for循环不断的向后,从而达到需要插入的位置
}
p->next=pre->next;
pre->next=p;
return List;
}
插入的关键部分:
p->next=pre->next;//p的指针域指向后进的节点
pre->next=p;//原本节点指向新的节点的地址
链表的删除
链表的删除跟插入同理,都需要两个节点,在通过把前驱的节点的指针域指向后一个的地址,也就是说获取下一个指针域的值,从而达到删除节点的效果。
LinkList List_Delete(LinkList list, int i){
Node *pre,*p;
p=list;
pre=p->next;
while (pre->data!=i){//到达所需要删除的节点的位置
p=pre;//p通过不断循环不断前进,但始终在pre节点之后,所以是pre的前驱
pre=pre->next;//不断指向下一个节点
}
p->next=pre->next;//pre节点的前驱指向pre节点的后进
free(pre);
return list;
}