数据结构学习笔记(单链表、单循环链表、带头双向循环链表)的增删查改排序等)

数据结构学习笔记(单链表、单循环链表、带头双向循环链表)的增删查改排序等

  • 链表的概念及结构
    • 链表结构的分类
  • 链表的常用操作实现
    • 无头单链表
      • 单链表补充
    • 单循环链表
    • 带头双向循环链表

链表的概念及结构

概念:
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
结构:
数据结构学习笔记(单链表、单循环链表、带头双向循环链表)的增删查改排序等)_第1张图片

链表结构的分类

  1. 单向、双向
  2. 带头、不带头
  3. 循环、非循环
    组合下来可分为8类链表结构:
    a:单向链表、双向链表
    b:不带头单链表、带头链表
    c:单链表、循环单链表
    d:无头单向非循环链表
    在这里插入图片描述
    e:带头双向循环链表
    数据结构学习笔记(单链表、单循环链表、带头双向循环链表)的增删查改排序等)_第2张图片

链表的常用操作实现

无头单链表

概念:单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
代码:

**结构代码**
// An highlighted block
typedef struct ListNode
{
	ElemType data;
	struct ListNode *next;
}ListNode;

typedef ListNode* List;//把链表定义为一个指针结构
**初始化**
// An highlighted block
void ListInit(List *plist)
{
	*plist = NULL;
}
**尾插**
// An highlighted block
void ListPushBack(List *plist, ElemType v)
{
	//申请节点
	ListNode *s = _Buynode(v);//此处写了一个购买节点的函数——buynode,在后面会写出来,在这里替代ListNode *s = (ListNode*)malloc(sizeof(ListNode));这样一个过程
	//插入节点
	ListNode *p = *plist;
	if(p == NULL)
	{
		*plist = s;
		return;
	}

	while(p->next != NULL)
		p = p->next;

	p->next = s;
}
**头插**
// An highlighted block
void ListPushFront(List *plist, ElemType v)
{
	ListNode *s = _Buynode(v);
	s->next = *plist;
	*plist = s;
}
**尾删**
// An highlighted block
void ListPopBack(List *plist)
{
	ListNode *p = *plist;
	ListNode *prev = NULL;
//判断是否为空
	if(*plist == NULL)
		return;
//	
	while(p->next != NULL)
	{
		prev = p;
		p = p->next;
	}
//判断头节点若为空直接返回空值,最后将删除的节点free掉,因为每一个节点都是用malloc函数申请的
	if(prev == NULL)
		*plist = NULL;
	else
		prev->next = NULL;
	free(p);
}
**头删**
// An highlighted block
void ListPopFront(List *plist)
{
	ListNode *p = *plist;
	if(*plist == NULL)//判断节点是否为头节点,若为空直接返回否定就指向下一个节点
		return;
//删除该节点与链表的连接
	*plist = p->next;
	free(p);//删除节点
}
显示链表内数据
// An highlighted block
var foo = 'bar';
**显示链表内数据**
// An highlighted block
void ListShow(List plist)
{
	ListNode *p = plist;
	while(p != NULL)
	{
		printf("%d->", p->data);
		p = p->next;
	}
	printf("Over.\n");//在循环体外面一定要有所返回或者输出的值
}
**查找链表中有效结点的个数**
// An highlighted block
size_t ListLength(List plist)
{
	ListNode *p = plist;
	size_t len = 0;
	while(p != NULL)
	{
		len++;
		p = p->next;
	}
	return len;
}
**查找数据**
// An highlighted block
ListNode* ListFind(List plist, ElemType key)
{
	ListNode *p = plist;
	while(p!=NULL && p->data!=key)
		p = p->next;
	return p;;
**删除节点**
// An highlighted block
void ListErase(List *plist, ElemType key)
{
	ListNode *p = *plist;
	ListNode *prev = NULL;
	if(p == NULL)//链表是否为空
		return;

	while(p!=NULL && p->data!=key)
	{
		prev = p;
		p = p->next;
	}
	if(p == NULL)
		return;

	if(prev == NULL)//考虑头节点
		*plist = p->next;
	else
		prev->next = p->next;//拷贝下一节点
	free(p);//更改有效节点数
}
**消除和摧毁**
// An highlighted block
void ListClear(List *plist)
{
	ListNode *p = NULL;
	while(*plist != NULL)
	{
		p = *plist;
		*plist = p->next;
		free(p);//对所有节点进行删除
	}
}
//直接引用消除是一样的效果
void ListDestroy(List *plist)
{
	ListClear(plist);
};
**按值插入**
// An highlighted block
void ListInsertByVal(List *plist, ElemType v)
{
    //默认在数据有序的前提下
	ListNode *p = NULL;
	ListNode *s = _Buynode(v);//申请节点
	if(*plist == NULL) //空链表
	{
		*plist = s;
		return;
	}
//如果插入的节点比第一个节点小
	if(v < (*plist)->data)
	{
		s->next = *plist;
		*plist = s;
		return;
	}
//查找节点
	p = *plist;
	while(p->next!=NULL && v>p->next->data)
		p = p->next;
//插入
	s->next = p->next;
	p->next = s;
};
**排序**
// An highlighted block
void ListSort(List *plist)
{
	ListNode *p;
	if(*plist==NULL || (*plist)->next==NULL)//只有一个节点或者空链表的时候不需要排序直接返回即可
		return;
	p = (*plist)->next;
	(*plist)->next = NULL; // 断开链表
	while(p != NULL)
	{
		ListNode *q = p->next;
		if(p->data < (*plist)->data)
		{
			p->next = *plist;
			*plist = p;
		}
		else
		{
			ListNode *prev = *plist;
			while(prev->next!=NULL && p->data>prev->next->data)
				prev = prev->next;
			p->next = prev->next;
			prev->next = p;
		}
		p = q;
	}
}
**反转**
// An highlighted block
void ListReverse(List *plist)
{
	ListNode *p = NULL;//声明定义的节点p并初始化为NULL
	if(*plist==NULL || (*plist)->next==NULL)
		return;

	p = (*plist)->next;//接收链表的下一个节点
	(*plist)->next = NULL; // 断开链表

	while(p != NULL)
	{
		ListNode *q = p->next
		//头插节点
		p->next = *plist;
		*plist = p;
		p = q;//p跳到q接着进行重新判断
	}
}

单链表补充

**此处写了一个购买节点的函数供调用,使得代码得到优化**
// An highlighted block
ListNode* _Buynode(ElemType v)
{
	ListNode *s = (ListNode*)malloc(sizeof(ListNode));
	assert(s != NULL);
	s->data = v;
	s->next = NULL;
	return s;
}

单循环链表

定义:循环单链表是单链表的另一种形式,其结构特点是: 链表中最后一个结点的指针域不再是结束标记,而是指向整个链表的第一个结点,从而使链表形成一个环。和单链表相同,循环链表也有带头结点结构和不带头结点结构两种,带头结点的循环单链表实现插入和删除操作较为方便。
结构
在这里插入图片描述
代码

**定义单循环链表**
// An highlighted block
typedef struct SCListNode
{
	ElemType data;
	struct SCListNode *next;
}SCListNode;

typedef struct SCList
{
	SCListNode *phead;
}SCList;

代码:

**初始化**
// An highlighted block
void SCListInit(SCList *plist)
{
	plist->phead = NULL;
}
**尾插**
// An highlighted block
void SCListPushBack(SCList *plist, ElemType v)
{
	SCListNode *s = (SCListNode *)malloc(sizeof(SCListNode));
	assert(s != NULL);
	s->data = v;
	s->next = NULL;

	SCListNode *p = plist->phead;
	if(p == NULL)
	{
		plist->phead = s;
		plist->phead->next = plist->phead;
		return;
	}

	while(p->next != plist->phead)
		p = p->next;

	s->next = plist->phead;
	p->next = s;
}

带头双向循环链表

定义:循环双链表是对双链表的改进,将尾结点与头结点建立连接,使得尾结点可以直接查找到头结点,头结点也能够直接查找到头结点,以此来提高查找的效率。
结构:
在这里插入图片描述
代码:

**结构体定义**
// An highlighted block
typedef struct DCListNode
{
	ElemType data;
	struct DCListNode *next;
	struct DCListNode *prev;
}DCListNode;

typedef struct DCList
{
	DCListNode *head;
}DCList;;
**初始化**
// An highlighted block
void DCListInit(DCList *plist)
{
	plist->head = _Buynode(-1);//此处也可设为0,头节点不具有相关值
}
**购买获取节点**
// An highlighted block
DCListNode* _Buynode(ElemType v)
{
	DCListNode *s = (DCListNode*)malloc(sizeof(DCListNode));
	assert(s != NULL);
	s->data = v;
	s->next = s->prev = s;
	return s;
}
**尾插**

在这里插入图片描述

// An highlighted block
void DCListPushBack(DCList *plist, ElemType v)
{
	DCListNode *s = _Buynode(v);
	s->next = plist->head;
	s->prev = plist->head->prev;
	s->next->prev = s;
	s->prev->next = s;
}
**头插**

数据结构学习笔记(单链表、单循环链表、带头双向循环链表)的增删查改排序等)_第3张图片

// An highlighted block
void DCListPushFront(DCList *plist, ElemType v)
{
	DCListNode *s = _Buynode(v);
	s->next = plist->head->next;
	s->prev = plist->head;
	s->next->prev = s;
	s->prev->next = s;
}
**尾删**

在这里插入图片描述

// An highlighted block
void DCListPopBack(DCList *plist)
{
	DCListNode *p;
	if(plist->head->next == plist->head)
		return;

	//查找最后一个节点
	p = plist->head->prev; 
	
	//删除节点
	p->next->prev = p->prev;
	p->prev->next = p->next;
	free(p);
}
**头删**
// An highlighted block
void DCListPopFront(DCList *plist)
{
	DCListNode *p = plist->head->next;
	if(plist->head->next == plist->head)
		return;

	p->prev->next = p->next;
	p->next->prev = p->prev;
	free(p);
}
**按值插入**
// An highlighted block
void DCListInsertByVal(DCList *plist, ElemType v)
{
	DCListNode *p = plist->head->next;
	while(p!=plist->head && v>p->data)
		p = p->next;

	DCListNode *s = _Buynode(v);
	s->next = p;
	s->prev = p->prev;
	s->next->prev = s;
	s->prev->next = s;
}
**查找**
// An highlighted block
DCListNode* DCListFind(DCList *plist, ElemType key)
{
	DCListNode *p = plist->head->next;
	while(p!=plist->head && key!=p->data)
		p = p->next;
	if(p == plist->head)
		return NULL;
	return p;
}
**按值删除**
// An highlighted block
void DCListErase(DCList *plist, ElemType key)
{
	DCListNode *p = DCListFind(plist, key);
	if(p == NULL)
		return;

	p->next->prev = p->prev;
	p->prev->next = p->next;

	free(p);
}
**查看循环双链表数据**
// An highlighted block
void DCListShow(DCList *plist)
{
	DCListNode *p = plist->head->next;
	while(p != plist->head)
	{
		printf("%d->", p->data);
		p = p->next;
	}
	printf("Over.\n");
}
**链表长度**
// An highlighted block
size_t DCListLength(DCList *plist)
{
	DCListNode *p = plist->head->next;
	size_t len = 0;
	while(p != plist->head)
	{
		len++;
		p = p->next;
	}
	return len;
}
**排序**
// An highlighted block
void DCListSort(DCList *plist)
{
	DCListNode *p, *q;
	size_t size = DCListLength(plist);
	if(size <= 1)
		return;

	p = plist->head->next;
	q = p->next;

	p->next = plist->head;
	plist->head->prev = p;

	while(q != plist->head)
	{
		p = q;
		q = q->next;

		//寻找插入的位置
		DCListNode *pos = plist->head->next;
		while(pos!=plist->head && p->data>pos->data)
			pos = pos->next;

		//插入节点
		p->next = pos;
		p->prev = pos->prev;
		p->next->prev = p;
		p->prev->next = p;
	}
}

下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
var foo = 'bar';
**反转**
// An highlighted block
void DCListReverse(DCList *plist)
{
	DCListNode *p, *q;
	size_t size = DCListLength(plist);
	if(size <= 1)
		return;

	p = plist->head->next;
	q = p->next;
	//断开链表
	p->next = plist->head;
	plist->head->prev = p;

	while(q != plist->head)
	{
		p = q;
		q = q->next;

		p->next = plist->head->next;
		p->prev = plist->head;
		p->next->prev = p;
		p->prev->next = p;
	}
}**加粗样式**
**清除**
// An highlighted block
void DCListClear(DCList *plist)
{
	DCListNode *p = plist->head->next;
	while(p != plist->head)
	{
		p->prev->next = p->next;
		p->next->prev = p->prev;
		free(p);

		p = plist->head->next;
	}
}
**摧毁**
// An highlighted block
void DCListDestroy(DCList *plist)
{
	DCListClear(plist);
	free(plist->head);
	plist->head = NULL;
}

你可能感兴趣的:(数据结构与算法,C语言,链表,数据结构)