IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 单循环,双向,双循环链表 -> 正文阅读

[数据结构与算法]单循环,双向,双循环链表

单向循环链表在这里插入图片描述

在这里插入图片描述
相比于单向链表,单向循环链表仅仅是将单向链表的尾节点指向了头节点

#include <stdio.h>
#include <stdlib.h>

typedef struct node{
	int data;           //数据域 
	struct node *next;  //指针域 
}Node;

//初始化
Node* InitList(){
	Node* head = (Node*)malloc(sizeof(Node));
	head->next = head;
	return head;
}


//判空
int IsEmpty(Node *head) {
	return head->next == head;
}


//在尾部插入
int InsertToListTail(Node *head, int data) {
	
	//新申请一个节点用于插入 
	Node *InsertNode = (Node*)malloc(sizeof(Node));
	InsertNode->data = data;
	//如果申请失败则返回0 
	if(!InsertNode) return 0;
	//找到尾节点 
	Node *p = head;
	while(p->next != head) p = p->next;
	//插入节点 
	InsertNode->next = p->next;
	p->next = InsertNode;
	
	return 1;
}


//删除指定节点
int DelFromList(Node *head, int data) {
	//如果链表为空返回0 
	if(IsEmpty(head))return 0;
	
	//分别找到要删除节点和它的前趋节点 
	Node *pre = head;
	Node *p = head->next;
	while(p->data != data && p != head) {
		pre = pre->next;
		p = p->next;
	}
	
	//如果找不到返回0 
	if(p == head) return 0;
	//删除节点 
	pre->next = p->next;
	free(p);
	return 1;
}


//修改指定节点
int UpdateList(Node *head, int index, int data) {
	//找到index所指的节点 
	Node *p = head->next;
	for(int i = 0; i < index && p!= head; i++ ) {
		p = p->next;
	}
	//如果index大于链表长度,则会在p==head是跳出循环 
	if(p == head) return 0;
	//修改数据 
	p->data = data;
	return 1;
} 


//找到指定节点
Node* FindNode(Node *head, int data) {
	//遍历链表找到对应节点 
	Node *p = head;
	while(p->data != data && p != head) {
		p = p->next;
	} 
	//如果没找到返回NULL,找到了则返回对应节点 
	if(p == head) return NULL;
	else          return p;
} 


//打印链表
void PrintList(Node *head) {
	if(head->next == head) printf("空链表");
	Node *p = head->next;
	while(p != head) {
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
} 

双向链表

//定义结构体变量
typedef struct node{
	int data;			//data域存放数据
	struct node *prev;	//prev指针域存放上一个结点的地址
	struct node *next;	//next指针域存放下一个结点的地址
}Node;

链表创建头结点[初始化]
在这里插入图片描述

/**
*创建链表,返回头指针。
**/
Node* initList(){
	Linklist head = (Linklist)malloc(sizeof(LNode));//创建头结点
	head->next=NULL;	//将next指针域置空
	head->prev=NULL;	//将prev指针域置空
	return head;		//返回头结点
}
/**
*双向链表判空操作
**/
int isEmpty(Linklist head){
	if(head->next==NULL && head->prev==NULL){
		//为空 
		return 1;
	}
	//不为空 
	return 0; 	
}

链表头插法创建
在这里插入图片描述
断开两个连接
在这里插入图片描述
特殊情况:

当只存在head结点时,head的next指针域为空。

在这里插入图片描述
已知Head结点和p结点,上面共四步:

Head->next=p;(1)
p->prev=Head;(2)
Head->next->prev=p;(3)
p->next=Head->next;(4)

3 4 1

/**
*头插法创建链表
**/
void ListByInsertHead(Node* head ){
	Node *p;	//指针p用来接受数据,进行插入
	int x;
	while(scanf("%d",&x)&&x!=-1){
		p=(Linklist)malloc(sizeof(LNode)) ;
		p->data=x;
	
    //头插法
    //只有头结点时,头结点的next域为NULL,不存在prev指针域,第一步要放在第三步之	 //前,此时未更新head->next
		if(head->next!=NULL){	
			head->next->prev=p;
		}
		p->next=head->next;	//单链表头插操作
		head->next=p;		//单链表头插操作
		p->prev=head;		//将p的prev指针域指向head(这一步放哪都行)
    
	}
	return ;
}

链表尾插法创建在这里插入图片描述
在这里插入图片描述
此时有四步改动

p->next=s;(1)
p=s;(2)
s->prev=p;(3)
s->next=p->next;(4)
//还有一种写法是s->next=NULL;

3 2

/**
*尾插法创建链表
**/
void ListByInsertTail(Node* head ){
    Node *p,*s;	//指针p用来保存尾指针位置,指针s用来存数据进行插入
    p=head;//只有头结点时,头结点即为最后一个结点
    int x;
    while(scanf("%d",&x)&&x!=-1){
        s=(Node*)malloc(sizeof(Node)) ;
        s->data=x;

        //尾插法
        s->next=p->next;//s的结点指向尾结点p的下一个,即NULL
        p->next=s;//将尾结点的next指针指向要插入的结点
        //第三步和第四步不能交换
        s->prev=p;//要插入的结点的前一个结点更新为尾结点
        p=s;//将尾结点更新为新插入的结点
        }

	return ;	
}
/**
*尾插法创建链表第二种写法
**/
void ListByInsertTail(Node* head ){
    Node *p,*s;	//指针p用来保存尾指针位置,指针s用来存数据进行插入
    p=head;//只有头结点时,头结点即为最后一个结点
    int x;
    while(scanf("%d",&x)&&x!=-1){
        s=(Node*)malloc(sizeof(Node)) ;
        s->data=x;

        //尾插法
        p->next=s;//将尾结点的next指针指向要插入的结点
        //第二步和第三步不能交换
        s->prev=p;//要插入的结点的前一个结点更新为尾结点
        p=s;//将尾结点更新为新插入的结点
    }
    s->next=NULL;//尾结点指向为空

    return ;	
}

指定结点前插入

在q结点前插入p结点
在这里插入图片描述

在这里插入图片描述
此处共有四处改动

p->prev=q->prev;(1)
q->prev->next=p;(2)
p->next=q;(3)
q->prev=p;(4)

/**
*指定结点前插入(在q结点前插入p结点)
**/

void Insert(Node *p, Node *q){
    //只有等q指针前面那个结点的相关操作处理完之后才能修改q->prev
	p->prev=q->prev;
	q->prev->next=p;
	p->next=q;
	q->prev=p;
}

链表删除
在这里插入图片描述
在这里插入图片描述
特殊:p为尾指针
在这里插入图片描述
上述有三处改动

p->prev->next=p->next;(1)
p->next=p->prev(2)
free(p)(3)
/**
*删除指定结点
**/

void delete_Node(Node *p){
	p->prev->next=p->next;
	if(p->next!=NULL){
		p->next->prev=p->prev;
	}                                                    
	free(p);
}

循环双向链表的实现

小思考:自己实现循环双向链表

循环双向链表和双向链表的操作基本一致, 注意由于head指针的prev域和尾指针的next域不为空,因此部分操作需要增加对这两个指针的连接

双向循环链表完整代码:

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
typedef struct node{
	int data;
	struct node *prev;
	struct node *next;
}LNode,*Linklist;

//创建链表
Linklist CreatList(); 

//双向循环链表判空操作
int isEmpty(Linklist head); 

//链表的创建 [头插法]
void ListByInsertHead(Linklist head );

//链表的创建[尾插法]
void ListByInsertTail(Linklist head );
 

//将p结点插入q结点之前 
void Insert(LNode *p, LNode *q);

//删除p结点
void delete_Node(LNode *p); 

//删除链表
void delete_List(LNode *p); 

//打印链表
void print_List(Linklist head);


int main(){
	
		Linklist head = CreatList();
		printf("%d\n",isEmpty(head));
	ListByInsertTail(head);
	print_List(head);
	printf("\n");
	//Linklist head1 = CreatList();
	//ListByInsertHead(head1);
	//print_List(head1);
	LNode *t = (Linklist)malloc(sizeof(LNode));
	t->data=10;
	Insert(t,head->next);
	print_List(head);
	printf("\n");
	delete_Node(t);
	print_List(head);
	delete_List(head);
	return 0;
	
} 

Linklist CreatList(){
	Linklist head = (Linklist)malloc(sizeof(LNode));
	head->next=head;
	head->prev=head;
	return head;
}

int isEmpty(Linklist head){
	if(head->next==head && head->prev==head){
		//为空 
		return 1;
	}
	//不为空 
	return 0; 	
}

void ListByInsertHead(Linklist head ){
	
	LNode *p;
	int x;
	while(scanf("%d",&x)&&x!=-1){
		p=(Linklist)malloc(sizeof(LNode)) ;
		p->data=x;
		
		head->next->prev=p;
		p->next=head->next;
		head->next=p;
		p->prev=head;
	}
	return ;
}

void ListByInsertTail(Linklist head ){

	LNode *p,*s;
	p=head;
	int x;
	while(scanf("%d",&x)&&x!=-1){
		s=(Linklist)malloc(sizeof(LNode)) ;
		s->data=x;
		s->next=p->next;
		//增加代码:尾指针所指的下一个结点即头指针的prev修改为要插入的结点,即将头指针与新要插入的结点连接起来
		p->next->prev=s; 
		p->next=s;
		s->prev=p;
		p=s;
	}
	return ;
	
	
}
				
void Insert(LNode *p, LNode *q){
	p->prev=q->prev;
	q->prev->next=p;
	p->next=q;
	q->prev=p;
}


void delete_Node(LNode *p){
	p->prev->next=p->next;
	//if(p->next!=NULL){ //p->next不会为空,可删去 
	p->next->prev=p->prev;
//	}                                                    
	free(p);
}

void delete_List(LNode *p){
	LNode *t,*temp;
	t=p->next;
	while(t!=p&&t!=p){//判断条件改为当t又绕回一圈时即链表只剩一个结点 
		temp=t->next;
		delete_Node(t);
		t=temp;
		print_List(p);
		printf("\n");
	}
	free(p);
}
void print_List(Linklist head){
	Linklist p;
	p=head->next;
	while(1){
	
		printf("%d ",p->data);	
		if(p->next==head){
			break;
		}	
		p=p->next;
	} 
	
	system("pause"); 
	printf("\n");
	while(1){	
		printf("%d ",p->data);
		
		if(p->prev==head){
			break;
		}
		p=p->prev;
	}
}
 

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-01 17:57:48  更:2021-12-01 17:58:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 14:50:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码