链表比较
单循环链表:和单链表相比,尾结点的next域不再保存NULL,而是保存上一个结点的地址
双向链表:和单链表相比,每个节点不仅仅只保存了一个节点的地址,还需要一个指针域保存上一个结点的地址
单循环链表存在的意义:可以从循环链表的任意一点出发,就可以遍历整个链表的所有结点,
双向链表存在的意义:每一个结点既可以找到直接后继,也可以找到直接前驱
单循环链表
增删查改等操作的思路
单循环链表代码思路大致与单链表相同,只是两种循环的停止条件变成了不等于头节点
初始化
初始化也就是没有有效结点,因此链表的头节点应该:
头节点的数据域浪费掉,不使用
头节点的next域,赋值为pclist
插入
0、安全性处理
1、购买新节点
2、找到合适的插入位置
3.插入
举例:尾插
0.安全性处理
1.购买新节点
2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
尾插,找尾结点,用指针p指向,通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点,此时,for循环,跑完,p指向尾结点。
(struct CNode* p = pclist;
for (; p->next != pclist; p = p->next);)
3.插入即可
删除
举例:头删来回顾思路
0:安全性处理(确保至少存在一个有效节点)
1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
2.找到待删除节点的前驱,用指针q指向,这里不用处理,因为这里pclist就可以代替q
3.跨越指向+释放
结构体设计
typedef int ELEM_TYPE;
typedef struct CNode
{
ELEM_TYPE data;//数据域
struct CNode* next;//指针域
}CNode, * PCNode;
//可实现的操作:
//初始化
void Init_clist(struct CNode* pclist);
//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val);
//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val);
//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val);
//头删
bool Del_head(PCNode pclist);
//尾删
bool Del_tail(PCNode pclist);
//按位置删
bool Del_pos(PCNode pclist, int pos);
//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val);
//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode* Search(PCNode pclist, ELEM_TYPE val);
//获取有效值个数
int Get_length(PCNode pclist);
//判空
bool IsEmpty(PCNode pclist);
//清空
void Clear(PCNode pclist);
//销毁1 无限头删
void Destroy1(PCNode pclist);
//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist);
//打印
void Show(PCNode pclist);
函数实现
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "clist.h"
//可实现的操作:
//初始化
void Init_clist(struct CNode* pclist)
{
//0.安全性处理
assert(pclist != NULL);
//1.对pclist指向的头结点里面的成员进行赋值:
//头结点的数据域不使用,只需要对指针域赋值即可,赋值为自身地址
pclist->next = pclist;
}
//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val) {
assert(pclist!=NULL);
struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
assert(pnewnode!=NULL);
pnewnode->data = val;
pnewnode->next = pclist->next;
pclist->next = pnewnode;
return true;
}
//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val)
{
//0.安全性处理
assert(pclist != NULL);
//1.购买新节点
struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
//尾插,找尾结点,用指针p指向
//通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点
struct CNode* p = pclist;
for (; p->next != pclist; p = p->next);
//此时,for循环,跑完,p指向尾结点
//3.插入即可
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val) {
assert(pclist != NULL);
struct CNode* pnewnode = (struct CNode*)malloc(1 * sizeof(struct CNode));
assert(pnewnode!=NULL);
pnewnode->data = val;
struct CNode* p = pclist;
for (int i = 0;i<pos;i++ ) {
p = p->next;
}
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
//头删
bool Del_head(PCNode pclist)
{
//0:安全性处理
assert(pclist != NULL);
if (IsEmpty(pclist))
{
return false;
}//确保至少存在一个有效节点
//1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
struct CNode* p = pclist->next;
//2.找到待删除节点的前驱,用指针q指向
//这里不用处理,因为这里pclist就可以代替q
//3.跨越指向+释放
pclist->next = p->next;
free(p);
return true;
}
//尾删
bool Del_tail(PCNode pclist) {
assert(pclist != NULL);
if (IsEmpty(pclist))
{
return false;
}
struct CNode* p = pclist;
for (; p->next != pclist; p = p->next);
struct CNode* q = pclist;
for (; q->next != p; q = q->next);
q->next = p->next;
free(p);
return true;
}
//按位置删
bool Del_pos(PCNode pclist, int pos) {
assert(pclist != NULL);
if (IsEmpty(pclist))
{
return false;
}
struct CNode* q = pclist;
for (int i = 0; i < pos; i++) {
q = q->next;
}
struct CNode* p = q->next;
q->next = p->next;
free(p);
return true;
}
//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val) {
assert(pclist != NULL);
struct CNode* p= Search(pclist, val);
if (p == NULL) {
return false;
}
struct CNode* q = pclist;
for (; q->next != p; q = q->next);
q->next = p->next;
free(p);
return true;
}
//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode* Search(PCNode pclist, ELEM_TYPE val) {
struct CNode* p = pclist->next;
for (; p != pclist; p = p->next) {
if (p->data == val) {
return p;
}
}
return NULL;
}
//获取有效值个数
int Get_length(PCNode pclist) {
assert(pclist != NULL);
struct CNode* p = pclist->next;
int count = 0;
for (; p != pclist; p = p->next) {
count++;
}
return count;
}
//判空
bool IsEmpty(PCNode pclist) {
return pclist->next== pclist;
}
//清空
void Clear(PCNode pclist) {
Destroy1(pclist);
}
//销毁1 无限头删
void Destroy1(PCNode pclist) {
/*while (IsEmpty(pclist)) {
Del_head(pclist);
}*/
while (pclist->next != pclist) {
struct CNode* p = pclist->next;
pclist->next = p->next;
free(p);
}
}
//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist) {
assert(pclist != NULL);
struct CNode* p = pclist->next;
struct CNode* q;
pclist->next = pclist;
while (p != pclist) {
q = p->next;
free(p);
p = q;
}
}
//打印
void Show(PCNode pclist)
{
//判定使用不需要前驱的for循环
struct CNode* p = pclist->next;
for (; p != pclist; p = p->next)
{
printf("%d ", p->data);
}
printf("\n");
}