数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)
Posted 康x呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)相关的知识,希望对你有一定的参考价值。
链表的概念及结构
概念:
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
结构:
链表结构的分类
- 单向、双向
- 带头、不带头
- 循环、非循环
组合下来可分为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, 以上是关于数据结构学习笔记(单链表单循环链表带头双向循环链表)的增删查改排序等)的主要内容,如果未能解决你的问题,请参考以下文章