单向循环链表
单向循环链表是一种特殊的单向链表,尾节点的指针指向头节点,形成一个闭环。适用于需要循环访问的场景,如轮询调度。
- 结构特点:每个节点包含数据域和指向下一个节点的指针,尾节点的指针指向头节点而非空值。
- 操作复杂度:
- 插入/删除头节点:O(1)
- 插入/删除尾节点:O(n)(需遍历到尾部)
- 代码示例(C++):
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
双向链表
双向链表的每个节点包含前驱和后继指针,支持双向遍历,但需要更多内存存储指针。
- 结构特点:节点包含前驱指针(
prev
)、数据域和后续指针(next
)。 - 操作复杂度:
- 任意位置插入/删除:O(1)(已知前驱节点时)
- 按值查找:O(n)
- 代码示例(C++):
struct DNode {
int data;
DNode* prev;
DNode* next;
DNode(int val) : data(val), prev(nullptr), next(nullptr) {}
};
作业:
1.双向链表的部分操作
#include "linklist.h"
int main(int argc, const char *argv[])
{
//定义一个头
linklistptr headptr=NULL;
//定义循环变量
int i;
//定义位置变量
int seat;
//头的初始化
headptr=LinklistHeadnodeApply();
//定义新输入数据
datatype nwedata;
//循环输入数据
for(i=0;i<5;i++)
{
puts("请输入一个数:");
scanf(" %d",&nwedata);
//调用双向链表的头插函数
LinklistHeadinsert(headptr,nwedata);
}
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//调用双向链表的遍历函数front
LinklistShowfront(headptr);
//循环输入数据
for(i=0;i<5;i++)
{
puts("请输入一个数:");
scanf(" %d",&nwedata);
//双向链表的尾插函数
LinklistTailinsert(headptr,nwedata);
}
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//调用双向链表的头删函数
LinklistHeaddelete(headptr);
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//调用双向链表的尾删函数
LinklistTaildelete(headptr);
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//分别输入位置和新数据
puts("输入想插入的位置:");
scanf(" %d",&seat);
puts("输入想插入的数据:");
scanf(" %d",&nwedata);
//调用双向链链表按位置插入函数
LinklistSeatinsert(headptr,seat,nwedata);
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//输入位置
puts("输入想删除的位置:");
scanf(" %d",&seat);
//调用双向链链表按位置插入函数
LinklistSeatdelete(headptr,seat);
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//分别输入位置和新数据
puts("输入想要修改的位置:");
scanf(" %d",&seat);
puts("输入想改成的数据:");
scanf(" %d",&nwedata);
//调用双向链链表按位置修改函数
LinklistSeatalter(headptr,seat,nwedata);
//调用双向链表的遍历函数next
LinklistShownext(headptr);
//输入位置
puts("输入想查找的位置:");
scanf(" %d",&seat);
//调用双向链链表按位置查找函数
LinklistSeatsift(headptr,seat);
return 0;
}
#ifndef _LINKLIST_H__
#define _LINKLIST_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
//返回值枚举
enum returntype
{
//失败返回
FAULSE=-1,
//成功返回
SUCCESS
};
//存储数据类型
typedef int datatype;
//双向链链表结构体
typedef struct Node
{
//数据域共用体
union
{
//头节点数据域
int len;
//普通节点数据域
datatype data;
};
//前向指针域
struct Node *front;
//后向指针域
struct Node *next;
}linklist,*linklistptr;
//头节点堆区申请函数
linklistptr LinklistHeadnodeApply(void);
//普通节点堆区申请函数
linklistptr LinklistComnodeApply(datatype nwedata);
//双向链表的头插函数
int LinklistHeadinsert(linklistptr headptr,datatype nwedata);
//双向链表的遍历函数next
int LinklistShownext(linklistptr headptr);
//双向链表的遍历函数front
int LinklistShowfront(linklistptr headptr);
//双向链表的尾插函数
int LinklistTailinsert(linklistptr headptr,datatype nwedata);
//双向链表的头删函数
int LinklistHeaddelete(linklistptr headptr);
//双向链表的尾删函数
int LinklistTaildelete(linklistptr headptr);
//双向链链表按位置插入函数
int LinklistSeatinsert(linklistptr headptr,int seat,datatype nwedata);
//双向链链表按位置删除函数
int LinklistSeatdelete(linklistptr headptr,int seat);
//双向链链表按位置修改函数
int LinklistSeatalter(linklistptr headptr,int seat,datatype nwedata);
//双向链链表按位置查找函数
linklistptr LinklistSeatsift(linklistptr headptr,int seat);
#endif
#include "linklist.h"
//头节点堆区申请函数
linklistptr LinklistHeadnodeApply(void)
{
//头节点堆区申请
linklistptr headptr=(linklistptr)malloc(sizeof(linklist));
//判断申请是否成功
if(headptr==NULL)
{
return NULL;
}
//初始化
headptr->len=0;
headptr->front=NULL;
headptr->next=NULL;
return headptr;
}
//普通点堆区申请函数
linklistptr LinklistComnodeApply(datatype nwedata)
{
//普通节点堆区申请
linklistptr comptr=(linklistptr)malloc(sizeof(linklist));
//判断申请是否成功
if(comptr==NULL)
{
return NULL;
}
//初始化
comptr->data=nwedata;
comptr->front=NULL;
comptr->next=NULL;
return comptr;
}
//双向链表的头插函数
int LinklistHeadinsert(linklistptr headptr,datatype nwedata)
{
//定义普通节点指针
linklistptr comptr=NULL;
//判断是否为null
if(headptr==NULL)
{
return FAULSE;
}
//普通节点申请
comptr=LinklistComnodeApply(nwedata);
//申请判断
if(comptr==NULL)
{
return FAULSE;
}
//头插
comptr->next=headptr->next;
comptr->front=headptr;
//判断是否为首个数据
if(headptr->next)
{
headptr->next->front=comptr;
}
headptr->next=comptr;
//个数自增
headptr->len++;
return SUCCESS;
}
//双向链表的遍历函数next
int LinklistShownext(linklistptr headptr)
{
//定义链表指针
linklistptr ptr=NULL;
//定义循环变量
int i;
//判断是否为null
//判断链表是否为空
if(headptr==NULL||headptr->len==0)
{
return FAULSE;
}
//输出
ptr=headptr->next;
puts("正序链表现有数据:");
while(ptr)
{
printf("%d ",ptr->data);
ptr=ptr->next;
}
putchar(10);
return SUCCESS;
}
//双向链表的遍历函数front
int LinklistShowfront(linklistptr headptr)
{
//定义链表指针
linklistptr ptr=NULL;
//定义循环变量
int i;
//判断是否为NULL
//判断链表是否为空
if(headptr==NULL||headptr->len==0)
{
return FAULSE;
}
//找尾部
ptr=headptr->next;
while(ptr->next)
{
ptr=ptr->next;
}
//输出
puts("逆序链表现有数据:");
while(ptr!=headptr)
{
printf("%d ",ptr->data);
ptr=ptr->front;
}
putchar(10);
return SUCCESS;
}
//双向链表的尾插函数
int LinklistTailinsert(linklistptr headptr,datatype nwedata)
{
//定义链表指针和普通节点指针
linklistptr ptr=NULL,comptr=NULL;
//判断头是否为null
if(headptr==NULL)
{
return FAULSE;
}
//找尾部
ptr=headptr;
while(ptr->next)
{
ptr=ptr->next;
}
//初始化普通节点
comptr=LinklistComnodeApply(nwedata);
//判断申请是否成功
if(comptr==NULL)
{
return FAULSE;
}
//尾插
ptr->next=comptr;
comptr->front=ptr;
//个数自增
headptr->len++;
return SUCCESS;
}
//双向链表的头删函数
int LinklistHeaddelete(linklistptr headptr)
{
//定义链表指针和将删节点指针
linklistptr deltr=NULL,ptr=NULL;
//判断头是否为null
if(headptr==NULL||headptr->len==0)
{
return FAULSE;
}
//找到要删除的数据第一个节点
deltr=headptr->next;
//头删
headptr->next=deltr->next;
//判断是否只有一个节点
if(deltr->next)
{
deltr->next->front=headptr;
}
free(deltr);
deltr=NULL;
//个数自减
headptr->len--;
return SUCCESS;
}
//双向链表的尾删函数
int LinklistTaildelete(linklistptr headptr)
{
//定义链表指针和将删节点指针
linklistptr deltr=NULL,ptr=NULL;
//判断头是否为null
if(headptr==NULL||headptr->len==0)
{
return FAULSE;
}
//找尾部
ptr=headptr;
while(ptr->next)
{
ptr=ptr->next;
}
ptr->front->next=NULL;
free(ptr);
ptr=NULL;
headptr->len--;
return SUCCESS;
}
//双向链链表按位置插入函数
int LinklistSeatinsert(linklistptr headptr,int seat,datatype nwedata)
{
//定义循环变量
int i;
//定义链表指针和普通节点指针
linklistptr ptr=NULL,comptr=NULL;
//判断头是否为NULL
//判断位置是否合法
if(headptr==NULL||seat<=0||seat>headptr->len+1)
{
return FAULSE;
}
//找到对应位置的前一个位置
ptr=headptr;
for(i=0;i<seat-1;i++)
{
ptr=ptr->next;
}
//初始化普通节点
comptr=LinklistComnodeApply(nwedata);
//
if(comptr==NULL)
{
return FAULSE;
}
//插入
comptr->next=ptr->next;
comptr->front=ptr;
if(ptr->next!=NULL)
{
ptr->next->front=comptr;
}
ptr->next=comptr;
headptr->len++;
return SUCCESS;
}
//双向链链表按位置删除函数
int LinklistSeatdelete(linklistptr headptr,int seat)
{
//定义循环变量
int i;
//定义链表指针和将删节点指针
linklistptr deltr=NULL,ptr=NULL;
//判断是否为NULL
//判断链表是否为空
//判断位置是否合法
if(headptr==NULL||headptr->len==0||seat<=0||seat>headptr->len)
{
return FAULSE;
}
//找到对应位置的前一个位置
ptr=headptr;
for(i=0;i<seat-1;i++)
{
ptr=ptr->next;
}
deltr=ptr->next;
ptr->next=deltr->next;
if(deltr->next!=NULL)
{
deltr->next->front=deltr->front;
}
free(deltr);
deltr=NULL;
headptr->len--;
return SUCCESS;
}
//双向链链表按位置修改函数
int LinklistSeatalter(linklistptr headptr,int seat,datatype nwedata)
{
//定义循环变量
int i;
//定义链表指针
linklistptr ptr=NULL;
//判断是否为NULL
//判断链表是否为空
//判断位置是否合法
if(headptr==NULL||headptr->len==0||seat<=0||seat>headptr->len)
{
return FAULSE;
}
//找到对应位置
ptr=headptr;
for(i=0;i<seat;i++)
{
ptr=ptr->next;
}
ptr->data=nwedata;
return SUCCESS;
}
//双向链链表按位置查找函数
linklistptr LinklistSeatsift(linklistptr headptr,int seat)
{
//定义循环变量
int i;
//定义链表指针
linklistptr ptr=NULL;
//判断是否为NULL
//判断链表是否为空
//判断位置是否合法
if(headptr==NULL||headptr->len==0||seat<=0||seat>headptr->len)
{
return NULL;
}
//找到对应位置
ptr=headptr;
for(i=0;i<seat;i++)
{
ptr=ptr->next;
}
printf("linklist[%d]=%d\n",seat,ptr->data);
return ptr;
}
运行示例:
2.牛客网刷题