2021-09-11

单链表

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值