数据结构4-线性表-双循环链表

循环链表

循环链表:是一种头尾相接的链表(即:表中最后一个结点的指针域
指向头结点,整个链表形成一个环)。
单循环链表:
image-20220628203413373

//单循环链表
#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0


typedef struct Node {
    int data;
    struct Node* next;
}Node;


Node* initList() {
    Node* L = (Node*)malloc(sizeof(Node));
    L -> data = 0;
    L -> next = L;
    return L;
}


void headInsert(Node* L, int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    node -> next = L -> next;
    L -> next = node;
    L -> data ++;
}


void tailInsert(Node* L, int data) {
    Node* n = L;
    Node* node = (Node*)malloc(sizeof(Node));
    node -> data = data;
    while(n -> next != L){
        n = n -> next;
    }
    node -> next = L;
    n -> next = node;
    L -> data ++;
}


int delete(Node* L, int data) {
    Node* preNode = L;
    Node* node = L -> next;
    while(node != L){
        if(node -> data == data){
            preNode -> next = node -> next;
            free(node);
            L -> data --;
            return TRUE;
        }
        preNode = node;
        node = node -> next;
    }
    return FALSE;
}

void printList(Node* L) {
    Node* node = L -> next;
    while(node != L){
        printf("%d->", node -> data);
        node = node -> next;
    }
    printf("NULL\n");
}

int main()
{
    Node* L = initList();
    headInsert(L, 1);
    headInsert(L, 2);
    headInsert(L, 3);
    headInsert(L, 4);
    headInsert(L, 5);
    tailInsert(L, 6);
    tailInsert(L, 7);
    printList(L);
    delete(L, 4);
    delete(L, 7);
    printList(L);
    return 0;
}

双循环链表:
在这里插入图片描述

优点:从表中任一结点出发均可找到表中其他结点。

空表:头结点存放自己的地址

判断循环链表的循环结束条件:p!=L ; p-> next != L


带尾指针的循环链表合并

循环链表是头尾相接的链表(即表中最后一个结点的指针域指向头结点,整个链表形成一个)(circular linked list)

**优点:**从表中任一结点出发均可访问全部结点

循环链表与单链表的主要差异当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同。

循环单链表的判别条件为p!=L或p->next!=L。
在这里插入图片描述
在这里插入图片描述
循环链表的定义

typedef struct CLnode
{
    ElemType data;
    CLnode *next;
}*CircList;

循环链表的初始化

void InitList(CircList &L)
{
    L = new CLnode;
    L->next = L;
}

循环链表的基本操作和单链表基本上相同,唯一不同的是,由于循环链表的最后一个结点的next不再是空指针,而是指向头结点,因此,循环中的结束条件要发生变化

单链表--------------循环链表
while(p)--------->while(p!=L)
while(p->next)--->while(p->next!=L)

双循环链表

有两个指针域,一个指向直接前驱,另一个指向直接后继

//双循环链表
//DuLinkList.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using std::cin;
using std::cout;
using std::endl;


//函数结果状态代码 
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1

//Status 是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef int ElemType;

typedef struct DuLNode
{
	ElemType data;
	struct DuLNode *prior;
	struct DuLNode *next;

}DuLNode, *DuLinkList;//表示类型
					 
Status InitList_Du(DuLinkList &L);

int ListEmpty_Du(DuLinkList L);

Status DestroyList_Du(DuLinkList &L);

Status ClearList_Du(DuLinkList &L);

int ListLength_Du(DuLinkList &L);

Status GetElem_Du(DuLinkList &L, int i, ElemType &e);

int  LocateELem_Du(DuLinkList L, ElemType e);

Status Listlnsert_Du(DuLinkList &L, int i, ElemType e);

Status Headlnsert_Du(DuLinkList &L, ElemType e);

Status ListDelete_Du(DuLinkList &L, int i, ElemType &e);

void ShowLinkList_Du(DuLinkList L);
//DuLinkList.cpp
#include "DuLinkList.h"

Status InitList_Du(DuLinkList &L)
{
	L = new DuLNode;
	L->data = 0;
	L->next = L->prior = L;
	return OK;
}

int ListEmpty_Du(DuLinkList L)
{
	if (L->next == L && L->prior == L)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

Status DestroyList_Du(DuLinkList &L)//销毁单链表L
{
	DuLNode * p;
	DuLNode * q;
	p = L->next;
	while (p && p != L)
	{
		q = p->next;
		delete p;
		p = q;
	}
	L->prior = L->next = L;
	delete L;
	return OK;
}

Status ClearList_Du(DuLinkList &L)
{
	DuLNode * p;
	DuLNode * q;
	p = L->next;
	while (p && p != L)
	{
		q = p->next;
		delete p;
		p = q;
	}
	L->prior = L->next = L;
	return OK;

}

int ListLength_Du(DuLinkList &L)
{
	DuLNode * p = L->next;
	int i = 0;
	while (p && p!=L)
	{
		p = p->next;
		i++;
	}
	return i;
}

Status GetElem_Du(DuLinkList &L, int i, ElemType &e)
{
	DuLNode * p = L->next;
	int j = 1;
	//初始化
	while (p && j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)return ERROR;//第i个元素不存在
	e = p->data;//取第1个元素
	return OK;
}


int  LocateELem_Du(DuLinkList L, ElemType e)
{
	DuLNode * p = L->next;
	int j = 1;
	//初始化
	while (p && p->data != e)
	{
		p = p->next;
		++j;
	}
	if (p)
	{
		return j;
	}
	else
	{
		return 0;
	}
}

Status Listlnsert_Du(DuLinkList &L, int i, ElemType e)
{


	DuLNode * p = L;
	int j = 0;
	//初始化
	while (p->next && j < i - 1)
	{
		p = p->next;
		++j;
	}

	DuLNode *s = new DuLNode;
	s->data = e;

	s->next = p->next;
	s->prior = p;
	p->next = s;
	p->next->prior = s;
	return OK;
}

Status Headlnsert_Du(DuLinkList &L, ElemType e)
{
	DuLNode *s = new DuLNode;
	s->data = e;

	s->next = L->next;
	s->prior = L->prior;

	L->next->prior = s;
	L->next = s;
	return OK;

}

Status ListDelete_Du(DuLinkList &L, int i, ElemType &e)
{
	DuLNode * p = L;
	int j = 0;
	//初始化
	while (p->next && j < i - 1)
	{
		p = p->next;
		++j;
	}
	DuLNode * pfree = p->next;
	e = pfree->data;

	p->next = p->next->next;
	p->next->next->prior = p;

	delete pfree;
	return OK;
}

void ShowLinkList_Du(DuLinkList L)
{
	DuLNode *p = L->next;
	while (p && p != L)
	{
		printf("%d, ", p->data);
		p = p->next;
	}
	printf("\n");
}

void test01()
{
	DuLinkList M;
	InitList_Du(M);
	if (M)
	{
		printf("链表初始化完成\n");
	}

	Listlnsert_Du(M, 1, 1);
	Listlnsert_Du(M, 2, 3);
	Listlnsert_Du(M, 3, 4);
	Listlnsert_Du(M, 2, 2);
	Listlnsert_Du(M, 1, 0);

	printf("双向循环链表的长度为:%d\n", ListLength_Du(M));
	ShowLinkList_Du(M);

	ElemType elem = 0;
	ListDelete_Du(M, 1, elem);
	printf("删除第一个元素%d  后链表为\n", elem);
	ShowLinkList_Du(M);

	printf("使用头插法添加6后链表为\n");
	Headlnsert_Du(M, 6);
	ShowLinkList_Du(M);


	ClearList_Du(M);
	if (ListEmpty_Du(M))
	{
		cout << "链表已经清空" << endl;
	}
	DestroyList_Du(M);

}
int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;

}

顺序表和链表的比较

  • 链式存储结构的优点:
    结点空间可以动态申请和释放;
    数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。

  • 链式存储结构的缺点:
    存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。

    链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。

存储密度是指结点数据本身所占的存储量和整个结点结构中
所占的存储量之比,即:
存储密度=-结点数据本身占用的空间 / 结点占用的空间总量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值