线性表——循环链表、双向链表

目录

一、循环链表

1、定义和特点

 2、初始化循环链表

 3、求循环链表的长度

4、遍历循环链表找到值为x的结点个数(重点在于遍历操作)

5、循环链表的典型应用——约瑟夫环

 二、双向链表

1、定义和特点

 2、双向链表的类型声明

3、求双向循环链表的长度

 4、双向循环链表插入算法

5、双向循环链表删除结点算法


 

一、循环链表

1、定义和特点

 

 注:以下算法中循环链表的节点声明同单链表

 2、初始化循环链表

  创建一个空的循环单链表,它只有头结点,由L指向它。该结点的next域指向该头结点

Status InitList(LinkList &L)
{
    L = (LinkList)malloc(sizeof(LNode));
    if(!L)
        exit(OVERFLOW);
    L->next = L;
    return Ok;
}

 3、求循环链表的长度

p初始指向头结点,当p再次指向头结点时,对循环链表的一轮遍历结束

int ListLength(LinkList L)
{
    int i = 0;
    LinkList p = L->next;  //p指向第一个结点
    while(p != L){ //如果没有到表尾
        i++;
        p = p->next;
    }
    return i;
}

4、遍历循环链表找到值为x的结点个数(重点在于遍历操作)

int CountNode(LNode *L, int x)
{
    int i = 0;
    LNode *p = L->next;
    while(p != L){
        if(p->data == x) i++;
        p = p->next;
    }
    return i;
}

5、循环链表的典型应用——约瑟夫环

 题解代码:

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
	int no;  //小孩的编号
	struct node* next; //指向下一个结点指针
}Child;
void CreateList(Child*& L, int n);
void Joseph(int n, int m);
void main()
{
	int n = 6, m = 5;
	printf("n=%d, m=%d:\n", n, m);
	Joseph(n, m);
	printf("\n");

}
//用尾插法创建不带头结点的小孩圈循环单链表
void CreateList(Child*& L, int n)
{
	int i;
	Child* p, * tc; //tc指向新建循环单链表的尾结点
	L = (Child*)malloc(sizeof(Child));
	L->no = 1;
	tc = L;
	for (i = 2; i <= n; i++)
	{
		p = (Child*)malloc(sizeof(Child));
		p->no = i;
		tc->next = p;
		tc = p;
	}
	tc->next = L;

}

//求解约瑟夫序列
void Joseph(int n, int m)
{
	int i, j;
	Child* L, * p, * q;  //注意这里L一直指向每一轮第一个报数的结点
	CreateList(L, n);
	for (i = 1; i <= n; i++)  //需要出列n个小孩
	{
		p = L;  //从L结点开始报数
		j = 1;
		while (j < m - 1) //报数报到L结点后的第m-1个结点
		{
			j++;  //报数递增
			p = p->next;  //移到下一个结点
		}
		q = p->next;  //报数到了第m个结点,用q来指向它
		printf("%d ", q->no); //将该节点出列,即输出
		p->next = q->next;  //在循环链表中删除该节点
		free(q);   //释放其空间
		L = p->next;  //下一个开始报数的结点
	}
}

运行结果

 二、双向链表

1、定义和特点

 2、双向链表的类型声明

    与单链表一样,双向链表也分为非循环的双向链表和双向循环链表,以下均是针对带头结点的双向循环链表

 

typedef struct DuLNode{
    ElemType data;
    DuLNode *prior, *next;
}DuLNode,*DuLinkList;

3、求双向循环链表的长度

其设计思路与单循环链表的算法完全相同

int ListLength(DuLinkList L)
{
    int i = 0;
    DuLinkList p = L->next; //p指向第一个结点
    while(p != L){ //p还没到表头时,继续循环
        i++;
        p = p->next;
    }
    return i;
}

 4、双向循环链表插入算法

    先在双向循环链表中查找第i-1个结点,若成功找到该节点(由p所指向),创建一个以e为值的新结点s,将s结点插入到p之后即可

 

Status ListInsert(DuLinkList L, int i, ElemType e)
{
    DuLinkList p, s;
    if(i < 1 || i > ListLength(L) + 1) //i的值不合法的情况下
        return ERROR;
    p = GetElemP(L, i - 1); //用p来保存第i的元素的前驱元素
    if(!p) return ERROR;
    s = (DuLinkList)malloc(sizeof(DuLNode));
    if(!s)
        exit(OVERFLOW);
    //将s插入到位置i
    s->data = p;
    s->next = p->next;
    p->next->prior = s;
    s->prior = p;
    p->next = s;
    return OK;
    
}

5、双向循环链表删除结点算法

    先在双向循环链表中找到第i个结点,若成功找到该结点(有p所指向),通过其前驱结点和后继结点的指针域的改变来删除p结点

 

Status ListDelete(DuLinkList L, int i, ElemType &e)
{
    DuLinkList p;
    if(i < i)
        return ERROR;
    p = GetElemP(L, i);  //用p来保存第i位置的元素
    if(!p)
        return ERROR;
    e = p->data;
    
    //将p结点从L中删除
    p->prior->next = p->next;
    p->next->prior = p->prior;
    //释放其空间
    free(p);
    return OK;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值