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

Posted 康x呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)相关的知识,希望对你有一定的参考价值。

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

链表的概念及结构

概念:
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
结构:

链表结构的分类

  1. 单向、双向
  2. 带头、不带头
  3. 循环、非循环
    组合下来可分为8类链表结构:
    a:单向链表、双向链表
    b:不带头单链表、带头链表
    c:单链表、循环单链表
    d:无头单向非循环链表

    e:带头双向循环链表

链表的常用操作实现

无头单链表

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

**结构代码**
// 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;
}
**头插**

// 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, 以上是关于数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)的主要内容,如果未能解决你的问题,请参考以下文章

数据结构入门带头双向循环链表(List)详解(初始化增删查改)

带头结点的双向循环链表及相应的操作

C语言带头双向循环链表增删改查的实现

C语言带头双向循环链表增删改查的实现

数据结构Java实现04----循环链表仿真链表

数据结构——带头双向循环链表