循环链表
循环链表:是一种头尾相接的链表(即:表中最后一个结点的指针域
指向头结点,整个链表形成一个环)。
单循环链表:
//单循环链表
#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;
}
顺序表和链表的比较
-
链式存储结构的优点:
结点空间可以动态申请和释放;
数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。 -
链式存储结构的缺点:
存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。
存储密度是指结点数据本身所占的存储量和整个结点结构中
所占的存储量之比,即:
存储密度=-结点数据本身占用的空间 / 结点占用的空间总量