1、头结点和头指针的区别
1.1区别:
头指针表明了链表的结点,可以唯一确定一个单链表。
头指针指向链表的第一个结点,其记录第一个存储数据的结点的地址。
头结点是点链表的第一个结点,若单链表有头结点,则头指针指向头结点;若单链表没有头结点,则指针指向第一个结点。
一个单链表可有没有头结点,但不能没有头指针。
头结点的数据域可以不存储任何数据。
1.2记录链表的类型不同:
头指针是一个4字节的指针,记录第一个存储数据的结点的地址。
头结点是一个结构体变量,使用这个变量的next域来记录第一个存储数据的结点的地址,头结点的data域可以使用联合体的方式记录链表的长度。
1.3各个操作方法的定义不同
如果是头指针实现,则方法中国接受这个链表的类型必须是二级指针。
头指针实现使用一级指针就OK。

2、头结点单链表
链表和顺序表的区别:
(1)链表在逻辑存储上是连续的,在物理存储上是不连续的。
(2)单链表属于链表中的一种,每一个存储数据的节点除了存储数据本身之外,还要存储其直接后继结点的地址。

例:32位系统存储10个整形(int 4个字节)数据:
顺序表存储 :总共需要堆区空间:40个字节
单链表存储: 总共需要堆区空间:80个字节
单链表的实现
头结点:

头指针——在实现代码中会使用二级指针

方法的声明:
#include<stdio.h>
typedef int DataType;typedef struct Node
{//数据类型union//结合体、联合体{DataType data;//存储元素int length;//存储元素个数};//结点指针类型struct Node *next;
}LinkList;//初始化
void InitLinkList(LinkList *head);//销毁
void DestroyLinkList(LinkList *head);//按位置插入插入
bool InsertPos(LinkList *head,DataType value,int pos);//头插
bool InsertFront(LinkList *head,DataType value);//尾插
bool InsertRear(LinkList *head,DataType value);//按位置删除
bool DeletePos(LinkList *head,int pos);//头删
bool DeleteFront(LinkList *head);//尾删
bool DeleteRear(LinkList *head);//按值删除
bool DeleteValue(LinkList *head,DataType value);//判空
bool IsEmpty(LinkList *head);//求长度
int GetLength(LinkList *head);//输出
bool PrintLinkList(LinkList *head);
方法的实现:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#include"head.h"static LinkList *ApplyNode(DataType value,LinkList *point )
{LinkList *new_node=(LinkList *)malloc(sizeof(LinkList));if(new_node==NULL) return NULL;new_node->data=value;new_node->next=point;return new_node;
}void InitLinkList(LinkList *head)
{if(head==NULL) exit(0);head->length=0;head->next=NULL;
}int GetLength(LinkList *head)
{if(head==NULL) exit(0);return head->length;
}bool InsertPos(LinkList *head,DataType value,int pos)
{if(head==NULL) exit(0);if(pos<0||pos>GetLength(head)) return false;LinkList *p=head;while(pos){p=p->next;pos--;}LinkList *new_node=ApplyNode(value,p->next);//生成新的结点if(new_node==NULL) return false;p->next=new_node;head->length++;return true;}bool InsertFront(LinkList *head,DataType value)
{if(head==NULL) exit(0);LinkList *new_node=ApplyNode(value,head->next);if(new_node==NULL) return false;head->next=new_node;head->length++;return true;
}bool InsertRear(LinkList *head,DataType value)
{if(head==NULL) exit(0);return InsertPos(head,value,GetLength(head));
}bool DeletePos(LinkList *head,int pos)
{if(head==NULL) exit(0);if(pos<0||pos>=head->length) return false;LinkList *p=head;while(pos){p=p->next;pos--;}LinkList *q=p->next;p->next=q->next;free(q);head->length--;return true;
}bool DeleteFront(LinkList *head)
{if(head==NULL) exit(0);return DeletePos(head,0);
}bool DeleteRear(LinkList *head)
{if(head==NULL) exit(0);return DeletePos(head,GetLength(head)-1);
}bool DeleteValue(LinkList *head,DataType value)
{if(head==NULL) exit(0);LinkList *p=head;LinkList *q=p->next;while(q!=NULL){if(q->data==value){p->next=q->next;free(q);q=p->next;head->length--;}else{p=q;q=q->next;}}return true;
}bool IsEmpty(LinkList *head)
{ if(head==NULL) exit(0);return head->length==0;
}bool PointLinkList(LinkList *head)
{if (head == NULL) exit(0);LinkList *p = head->next;while (p != NULL){printf("%d ", p->data);p = p->next;}printf("\n");
}
void DestroyLinkList(LinkList *head)
{if(head=NULL) exit(0);while(IsEmpty(head)!=NULL){DeleteFront(head);}
}//找到第K个结点
LinkList *FindK(LinkList *head, int k) // 0< k <= length
{if (head == NULL) return NULL;if (k <= 0 || k > head->length) return NULL;int pos = head->length - k + 1;LinkList *p = head;while (pos){p = p->next;pos--;}return p;
}// 不能直接获得length的情况
LinkList *FindOfK2(LinkList *head, int k)
{if (head == NULL) return NULL;if (k <= 0) return NULL;LinkList *p = head;while (k && p != NULL){p = p->next;k--;}if (p == NULL) return NULL;LinkList *q = head;while (p != NULL){p = p->next;q = q->next;}return q;
}//O(1)删除非尾结点p
bool DeletePos1(LinkList *head,int pos)
{if(head==NULL) return false;if(pos<0||pos>=head->length) return false;LinkList *p=head;while(pos){p=p->next;pos--;}LinkList *q=p->next;p->next=q->next;free(q);head->length--;return true;}//将单链表逆置 -- 结点逆置
void Reverse(LinkList *head)
{if(head==NULL) return;LinkList *p=NULL;LinkList *q=head->next;LinkList *s=q->next;while(q!=NULL){q->next=p;p=q;q=s;if(s!=NULL) s=s->next;}head->next=p;
}
//判断两个结点是否相交,返回相交的第一个结点
LinkList *IsIntersect(LinkList *head1,LinkList *head2)
{if(head1==NULL||head2==NULL) return false;LinkList *p=head1;LinkList *q=head2;if(head1->length>head2->length){for(int i=0;i<head1->length-head2->length;i++){p=p->next;}}else{for(int i=0;i<head2->length-head1->length;i++){q=q->next;}}while(p!=q){p=p->next;q=q->next;}return p;
}LinkList *IsIntersect2(LinkList *head1, LinkList *head2)
{if (head1 == NULL || head2 == NULL) return NULL;LinkList *p = head1;LinkList *q = head2;while (p != q){if (p != NULL) p = p->next;else p = head2;if (q != NULL) q = q->next;else q = head1;
// p = p != NULL ? p->next : head2;
// q = q != NULL ? q->next : head1;}return p;
}
//判断单链表是否有环,如果有,返回入环的第一个结点
LinkList *IsLoop(LinkList *head)
{if(head==NULL) return NULL;LinkList *fast=head;LinkList *slow=head;while(fast!=NULL&&fast->next!=NULL){fast=fast->next->next;slow=slow->next;if(fast==slow) break;}LinkList *p=fast;LinkList *q=slow;while(q!=p){p=p->next;q=q->next;}return p;
}int main()
{LinkList list;InitLinkList(&list);InsertFront(&list,1);InsertPos(&list,2,1);InsertRear (&list,3);InsertRear (&list,4);InsertRear (&list,5);DeletePos(&list,1);printf("单链表长度为:%d\n",GetLength(&list));printf("第一次输出:");PointLinkList(&list);DeleteValue(&list,4);InsertPos(&list,2,1);printf("第二次输出:");PointLinkList(&list);return 0;
}
3、头指针单链表

方法的声明:
#include<stdio.h>
typedef int DataType;typedef struct Node
{DataType data; // 记录本结点存储的数据struct Node *next; // 记录下一个结点的地址
}LinkList;// 初始化
void InitLinkList(LinkList **phead);
// 插入
bool InsertLinkList(LinkList **phead, DataType value, int pos);bool InsertLinkListHead(LinkList **phead, DataType value);bool InsertLinkListRear(LinkList **phead, DataType value);// 删除
bool DeleteLinkList(LinkList **phead, int pos);bool DeleteLinkListHead(LinkList **phead);bool DeleteLinkListRear(LinkList **phead);// 长度
int GetLength(LinkList **phead);
// 判空
bool Empty(LinkList **phead);
// 销毁
void DestroyLinkList(LinkList **phead);// 显示
void ShowLinkList(LinkList **phead);
方法的实现:
#include "head.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>static LinkList *ApplyNewNode(DataType value, LinkList *next)
{LinkList *new_node = (LinkList *)malloc(sizeof(LinkList));if (new_node == NULL) exit(0);new_node->data = value;new_node->next = next;return new_node;
}void InitLinkList(LinkList **phead) // phead中存储的值就是main方法中的phead变量的地址
{if (phead == NULL) exit(0);*phead = NULL;
}int GetLength(LinkList **phead)
{if (phead == NULL) exit(0);int length = 0;LinkList *p = *phead;while (p != NULL){length++;p = p->next;}return length;
}bool InsertLinkList(LinkList **phead, DataType value, int pos)
{if (phead == NULL) exit(0);if (pos < 0 || pos > GetLength(phead)) return false;// 在头指针的后面插入新结点,头插法必须特殊处理: 因为只有在这需要修改头指针的值if (pos == 0) return InsertLinkListHead(phead, value);// 头插LinkList *p = *phead;while (pos > 1){p = p->next;pos--;}// while循环结束后,就需要在p所指向的结点的后面插入新结点/* LinkList *new_node = ApplyNewNode(value, p->next); p->next = new_node;*/p->next = ApplyNewNode(value, p->next);return true;
}bool InsertLinkListHead(LinkList **phead, DataType value)
{if (phead == NULL) exit(0);*phead = ApplyNewNode(value, *phead);return true;
}bool InsertLinkListRear(LinkList **phead, DataType value)
{if (phead == NULL) exit(0);// 链表本身是空的,尾插相当于头插if (Empty(phead)) return InsertLinkListHead(phead, value);LinkList *p = *phead;while (p->next != NULL) p = p->next; // while循环结束后,p就是最后一个结点p->next = ApplyNewNode(value, NULL);return true;
}bool Empty(LinkList **phead)
{if (phead == NULL) exit(0);if (*phead == NULL) return true;return false;
}bool DeleteLinkList(LinkList **phead, int pos)
{if (phead == NULL) exit(0);if (pos < 0 || pos >= GetLength(phead)) return false;if (pos == 0) return DeleteLinkListHead(phead);LinkList *p = *phead; // p指向的是第一个数据结点while (pos > 1){p = p->next;pos--;}// while循环结束后,要删除的结点时p->nextLinkList *q = p->next;p->next = q->next;free(q);return true;
}bool DeleteLinkListHead(LinkList **phead)
{if (phead == NULL) exit(0);if (Empty(phead)) return false;LinkList *p = *phead;*phead = p->next;free(p);return true;
}bool DeleteLinkListRear(LinkList **phead)
{if (phead == NULL) exit(0);if (Empty(phead)) return false;LinkList *front = NULL;LinkList *p = *phead;while (p->next != NULL){front = p;p = p->next;}if (front == NULL) return DeleteLinkListHead(phead);front->next = NULL;free(p);return true;
}void DestroyLinkList(LinkList **phead)
{if (phead == NULL) exit(0);while (!Empty(phead)){DeleteLinkListHead(phead);}
}void ShowLinkList(LinkList **phead)
{if (phead == NULL) exit(0);LinkList *p = *phead;while (p != NULL){printf("%d ", p->data);p = p->next;}printf("\n");
}int main()
{LinkList *list;InitLinkList(&list);InsertLinkListHead(&list,6);InsertLinkListHead(&list,5);InsertLinkListHead(&list,4);InsertLinkListHead(&list,3);InsertLinkListHead(&list,2);InsertLinkListHead(&list,1);DeleteLinkList (&list,5);printf("第一次输出:");ShowLinkList(&list);InsertLinkList(&list,6,5);InsertLinkListRear(&list,7);DeleteLinkListHead(&list);DeleteLinkListRear(&list);printf("第一次输出:");ShowLinkList(&list);return 0;
}
头指针单链表操作时的转化
因为头结点实现的单链表相比于头指针实现的单链表,操作时特殊情况少一些。在实现一些有指针的单链表的操作时,可以虚拟构建出一个头结点。
bool Funaction(LinkList **phead)
{//虚拟出来的头结点LinkList *head=(LinkList *)malloc(sizeof(LinkList));head->next =*phead;LinkList *p=head;//p指向头结点LinkList *q=p->next;while(q->next!=NULL){p=q;q=q->next;}p->next=q->next ;free(q);*phead=head->next;free(head);
}

















