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->next
LinkList *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);
}