单链表
1、单链表的概念
链表在逻辑存储上是连续的,在物理存储上是不连续的。
单链表属于链表中的一种,每一个存储数据的节点除了存储数据本身之外,还需要存储直接后继结点的地址。
例:32位系统存储10个整形(int 4个字节)数据:
顺序表存储:总共需要的堆区空间:40个字节
单链表存储:总共需要的堆区空间:80个字节
2、单链表的实现
头结点单链表、头指针单链表
3、头结点单链表
(1)结构声明
typedef int DataType;
typedef struct Node
{
//数据类型
union //联合体 共同体
{
DataType data;//存储有效数据的
int length;//头结点使用,来存储结点个数的
};
//结点指针类型
struct Node *next;
}LinkList;
(2)方法的声明
//初始化
void InitLinkList(LinkList *head);
//销毁
void DestroyLinkList(LinkList *head);
//插入
bool InsertLinkList(LinkList *head,DataType value,int pos);
bool InsertLinkListHead(LinkList *head,DataType value);
bool InsertLinkListRear(LinkList *head,DataType value);
//bool InsertLinkListValueBefore();
//bool InsertLinkListValueAfter();
//删除
bool DeleteLinkList(LinkList *head,int pos);
bool DeleteLinkListHead(LinkList *head);
bool DeleteLinkListRear(LinkList *head);
bool DeleteLinkListValue(LinkList *head,DataType value);
//判空
bool EmptyLinkList(LinkList *head);
//长度
int GetLength(LinkList *head);
//显示
void ShowLinkList(LinkList *head);
(3)方法的实现
#include "head_list.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.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 InsertLinkList(LinkList *head,DataType value,int pos)
{
if(head == NULL) exit(0);
if(pos < 0 || pos > GetLength(head)) return false;
//找pos位置的前面一个结点
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 InsertLinkListHead(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 InsertLinkListRear(LinkList *head,DataType value)
{
if(head == NULL) exit(0);
return InsertLinkList(head,value,GetLength(head));
}
//删除
bool DeleteLinkList(LinkList *head,int pos)
{
if(head == NULL) exit(0);
if(pos < 0 || pos >= GetLength(head)) return false;
LinkList *p = head;
while(pos)
{
p = p->next;
pos--;
}
//需要删除的节点是p的后继结点
LinkList *q = p->next;
p->next = q->next;
free(q);
head->length--;
return true;
}
bool DeleteLinkListHead(LinkList *head)
{
if(head == NULL);
return DeleteLinkList(head,0);
}
bool DeleteLinkListRear(LinkList *head)
{
if(head == NULL) exit(0);
return DeleteLinkList(head,GetLength(head)-1);
}
//考虑有重复值的情况
bool DeleteLinkListValue(LinkList *head,DataType value)
{
if(head == NULL) exit(0);
LinkList *p = head;
LinkList *q = head->next;
while(q != NULL)
{
if(q->data == value)
{
p->next = q->next;
free(q);
q = p->next;
head->length--;
}
else
{
p = q;
q = p->next;
}
}
return true;
}
bool EmptyLinkList(LinkList *head)
{
if(head == NULL) exit(0);
return head->length == 0;
}
void ShowLinkList(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(!EmptyLinkList(head))
{
DeleteLinkListHead(head);
}
}
3、头指针单链表
(1)结构声明
typedef int DataType;
typedef struct Node
{
DataType data;//记录本结点存储的数据
struct Node *next;//记录下一个结点的地址
}LinkList;
(2)方法的声明
//初始化
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);
(3)方法的实现
#include "list.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 = nxet;
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;
}
void ShowLinkList(LinkList **phead)
{
if(phead == NULL) exit(0);
LinkList *p = *phead;
while(p != NULL)
{
printf("%d",p->data);
p = p->next;
}
printf("\n");
}
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);
}
}
头指针单链表操作时的转化:
因为头结点实现的单链表相比于头指针实现的单链表,操作时特殊情况能少一些。在实现一些头指针的单链表的操作时,可以虚拟建出一个头结点。
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 = p->next;
}
p->next = q->next;
free(q);
*phead = head->next;
free(head);
}
作业
1、找倒数第k个结点
2、将单链表逆置–结点逆置
3、O(1)删除非尾结点p
4、判断两个单链表是否相交并返回相交的第一个结点
5、判断单链表是否有环,如果有,返回入环的第一个结点
LinkList *FindOfk(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;
}
bool DeleteOfNode(LinkList *head,LinkList *p)
{
if(head == NULL || p == NULL) return false;
if(p->next == NULL) return DeleteLinkListRear(head);
LinkList *q = p->next;
p->data = q->data;
p->next = q->next;
free(q);
return true;
}
void Reverse(LinkList *head)
{
if(head == NULL || head->next == 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 || head == NULL) return NULL;
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;
}
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(slow == fast) break;
}
if(fast == NULL || fast->next == NULL) return NULL;
LinkList *p = fast;
LinkList *q = head;
while(p != q)
{
p = p->next;
q = q->next;
}
return p;
}