数据结构第二章 线性表

1 线性表的概念

线性表(List)概念:由n个类型相同的数据元素组成的有限序列。(类似排队,具有线一样性质的结构。)

线性表性质:

  1. 同一性:元素类型相同
  2. 有穷性:有限元素
  3. 有序性:存在序偶关系

2 线性表的顺序存储

2.1 顺序表存储结构

用一组地址连续的存储单元依次存储线性表中的各个元素,其物理结构和逻辑结构一致。可以将顺序表归纳为:“关系线性化,结点顺序存”。

顺序表第i个元素所在地址的计算:Loc(ai) = Loc(a1) + (n-1) * k。其中Loc(a1) 称为基地址,k是每个元素所占单元数。

2.2 顺序表抽象数据类型定义

C语言代码如下:

#define MAXSIZE 255

typedef struct {
	ElemType elem[MAXSIZE];
	int last;  //记录线性表最后一个元素在elem[]中的位置(下标),空表为-1
}SeqList;

说明:

  • Elem 应该根据实际情况而定,可以是int、double、char等
  • 变量L的定义和使用的两种方式:
    • 通过变量定义语句:
      • SeqList L;
      • 利用L.elem[i-1]访问第i个元素,利用L.last得到顺序表最后一个元素的下标,L.last+1是顺序表长度。
    • 通过指针变量定义语句:
      • SeqList L1, *L; L = &L1;
      • 利用L -> elem[i-1]访问第i个元素,利用L -> last +1得到顺序表长度

2.3 顺序表基本运算

2.3.1 查找

int SeqSearch(SeqList L, ElemType e)
{
    int i = 0;
    while((i<=L.last)&&(L.elem[i]!=e))
    {
        i++;
    }
    if(i<=L.last)
        return (i+1);  //i是e元素在elem[]中的下标,i+1是e元素在线性表中的位置
    else
        return(-1);  //e不在elem[]中,返回-1
}

2.3.2 插入

#define OK 1
#define ERROR 0

int SeqInsert(SeqList *L, int i, ElemType e)
/*
    在顺序表第i个位置之前插入一个元素e
*/
{
    int k;
    if((i<1)||(i>L->last+2))
    {
        printf("插入位置i值不合法");
        return ERROR;
    }
    if(L->last >= MAXSIZE -1)
    {
        printf("表已满,无法插入");
        return ERROR;
    }
    for(k = L->last; k>= i-1; k--)
    {
        L->elem[k+1] = L->elem[k];
    }
    L->elem[i-1] = e;
    L->last++;
    return OK;
}

2.3.3 删除

#define OK 1
#define ERROR 0

int SeqDelete(SeqList *L,int i, ElemType *e)
/*
    删除在顺序表第i个位置的元素,用e返回其值
*/
{
    int k;
    if((i<1)||(i>L->last+1))
    {
        printf("删除位置不合法");
        return ERROR;
    }
    e = L->elem[i-1];
    for(k = i; k<= L->last; k++)
    {
        L->elem[k-1] = L->elem[k];
    }
    L->last--;
    return OK;
}

2.3.4 合并

前提:
有两个顺序表LA和LB,其元素均为非递减有序排列,编写一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序排列

算法思想:
设表LC是一个空表。设置两个指针i、j分别指向表LA和LB中的元素。

  • 若LA.elem[i] ≤ LB.elem[j],则先将LA.elem[j]插入到表LC中
  • 若LB.elem[i] ≤ LA.elem[j],则先将LB.elem[i]插入到表LC中
  • 最后再将未扫描完的表中剩余的所有元素放到表LC中
void MergeSeqList(SeqList *LA, SeqList *LB, SeqList *LC)
{
    int i=0,j=0,k=0,l;
    while(i<=LA->last && j<=LB->last)
    {
        if (LA->elem[i] <= LB->elem[j])
        {
            LC->elem[k] = LA->elem[i];
            i++;
            k++;
        }
        else
        {
            LC->elem[k] = LB->elem[j];
            j++;
            k++;
        }
    }
    while(i<=LA->last)
    {
        LC->elem[k] = LA->elem[i];
        i++;
        k++;
    }
    while(j<=LB->last)
    {
        LC->elem[k] = LA->elem[j];
        j++;
        k++;
    }
    LC->last = LA->last+LB->last+1;
}

2.4 顺序存储的优点和缺点

2.4.1 优点

  1. 无需为表示结点间的逻辑关系而增加额外的存储空间。
  2. 可方便地随机存取表中的任一元素。

2.4.2 缺点

  1. 插入或删除运算不方便,除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,效率较低。
  2. 由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配。因此当表长变化较大时,难以确定合适的存储规模。

3 线性表的链式存储

3.1 链表的概念

概念:用一组任意的存储单元存储线性表的数据元素。每一个数据元素就是一个结点,包括数据域和指针域。

结点:数据元素信息(数据域:data)+ 后继结点的地址(指针域:next

3.2 单链表

概念:只有一个next指针域的线性链表。链表里每个结点的存储地址存放在前驱结点的指针域中。由于线性表第一个结点无前驱,所以应该设一个头指针H指向第一个结点。由于线性表最后一个结点没有直接后继,指定单链表最后一个结点的指针域为空

3.2.1 单链表抽象数据类型定义

C语言代码如下:

typedef struct Node{
	ElemType data;
	struct Node *next;  //记录线性表最后一个元素在elem[]中的位置(下标),空表为-1
}Node, *LinkList;

说明:LinkList与Node * 同为结构指针类型,两种类型等价。通常习惯用LinkList说明指针变量,强调它是某个单链表的头指针变量。用Node*来定义单链表中结点的指针,表明指向单链表中结点的指针变量

3.2.2 初始化单链表

InitList(LinkList *L)
{
	*L = (LinkList)malloc(sizeof(Node)); //建立头节点
    (*L)->next = NULL;  //建立空的单链表L*
}

3.2.3 单链表的建立

头插法建表:

void GreatFromHead(LinkList L)
{
    Node *s;
    char c;
    int flag = 1;
    while(flag)
    {
        c = getchar();
        if(c!='$')
        {
            s = (Node * )malloc(sizeof(Node));//建立新结点s
            s->data = c;
            s->next = L->next;
            L->next = s;
        }
        else
            flag = 0;
    }
}

尾插法建表(推荐):

void GreatFromTail(LinkList L)
{
    Node *s, *r;
    char c;
    int flag = 1;
    r = L;
    while(flag)
    {
        c = getchar();
        if(c!='$')
        {
            s = (Node * )malloc(sizeof(Node));//建立新结点s
            s->data = c;
            r->next = s;
            r = s;
        }
        else
        {
            flag = 0;
            r->next = NULL;
        }
    }
}

3.2.4 单链表的查找

按序号查找

Node * Get(LinkList L, int i)
{
	if(i<=0)
        return null;
    int j = 0;
    Node *p
    p = L;
    while((p->next!=NULL)&&(j<i))
    {
     p = p->next;
     j++;   
    }
    if(j==i)
        return p;
    else
        return NULL;
}

按值查找

Node * Locate(LinkList L, ElemType key)
{
    Node * p;
    p = L->next;
    while(p!=NULL)
    {
        if(p->data!=key)
            p = p->next;
        else
            break;
    }
    return p;
}

3.2.5 单链表的插入

void InsList(LinkList L, int i, ElemType e)
{
	//第i个数据元素之前插入一个数据元素e
	if(i<=0)
        return ERROR;
    Node *pre, *s;
    int k = 0;
    pre = L;
    while(pre!=NULL && k<i-1)
    {
        pre = pre->next;
        k++;
    }
    if(pre==NULL)
    {
        printf("插入位置不合理!");
        return ERROR;
    }
    s = (Node*)mallcon(sizeof(Node))
    s->data = e;
    s->next = pre->next;
    pre->next = s;
    return OK;
}

3.2.6 单链表的删除

int DelList(LinkList L, int i,ElemType e)
{
    Node *pre,*r;
    int k=0;
    pre = L;
    while(pre->next!=NULL&&k<i-1)
    {
        pre=pre->next;
        k++;
    }
    if(pre->next==NULL)
    {
        printf("删除结点的位置不合理!");
        return ERROR;
    }
    r = pre->next;
    pre->next = r->next;
    *e = r->data;
    free(r);
    return OK;
}

3.2.7 两个单链表的差

前提:假设集合A用单链表LA表示,集合B用单链表LB表示,设计算法求两个集合的差,即A-B。

void Difference (LinkList LA,LinkList LB) 
/*此算法求两个集合的差集*/
{ 
	Node *pre, *p, *r;
	pre=LA;
	p=LA->next; /*p是表中的某一结点,pre始终指向p的前驱*/
	while(p!=NULL){
		q=LB->next; /*扫描LB中的结点,寻找与LA中*P结点相同的结点*/
		while (q!=NULL&&q->data!=p->data) 
			q = q->next;
		if (q!=NULL){ 
			r = p; 
			pre->next = p->next; 
			p = p->next; 
			free(r); 
		}
		else{ 
			pre = p;
			p = p->next; 
		}
	}
}

3.3 循环链表

概念:循环链表是一个首尾相接的链表。

特点:

  • 表中最后一个结点的指针指向第一个结点或表头结点(如有表头结点的话)。
  • 循环链表的运算与线性链表基本一致。但两者判断是否到表尾的条件不同。

3.3.1 循环链表抽象数据类型定义

typedef struct Node
{
    ElemType data;
    struct Node * next;
}Node,*LinkList;

3.3.2 初始化循环链表

InitCLinkList(LinkList *CL)
{
    *CL = (LinkList)malloc(sizeof(Node));
    (*CL)->next = *CL;
}

3.3.3 循环链表的建立

void GreateCLinkList(LinkList *CL)
{
    Node *rear, *s;
    char c;
    rear =  CL;
    c = getchar();
    while(c!='$')
    {
        s = (Node * )malloc(sizeof(Node));
        s->data = c;
        rear->next = s;
        rear = s;
        c = getchar();
    }
    rear->next = CL;
}

3.3.4 循环链表的合并

//循环单链表合并算法1
LinkList merge_1(LinkList LA, LinkList LB)
{
    Node *p,*q;
    p = LA;
    q = LB;
    while(p->next!=LA) p = p->next;
    while(q->next!=LB) q = q->next;
    q->next = LA;
    p->next = LB->next;
    free(LB);
    return(LA);
}

//循环单链表合并算法2
//RA、RB指向表尾
LinkList merge_2(LinkList RA, LinkList RB)
{
    Node *p;
    p = RA->next;
    RA->next = RB->next->next;
    free(RB->next);
    RB->next = p;
    return RB;
}

3.4 双向链表

结点:prior(前驱指针域)、data(数据域)、next(后继指针域)
双向链表结点结构

3.4.1 双向链表抽象数据类型定义

#define ERROR 0
#define OK 1

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next;
}DNode,*DoubleList;

3.4.2 双向链表的插入

int DlinkIns(DoubleList L,int i,ElemType e)
{
    if(i<0) 
    	return ERROR;
    DNode *s, *p;
    int k = 0;
    p = L;
    while(p!=NULL && k<i)
    {
        p = p->next;
        k++;
    }
    if(p==NULL)
    {
        printf("插入位置不合理!");
        return ERROR;
    }
    s = (DNode * )malloc(sizeof(DNode));
    if(s)
    {
        s->data = e;
        s->prior = p->prior;
        p->prior->next = s;
        s->next = p;
        p->prior = s;
        return OK;
    }
    else
        return ERROR;
}

3.4.3 双向链表的删除

int DlinkDel(DoubleList L,int i,ElemType *e)
{
    if(i<0) 
    	return ERROR;
    DNode *p;
    int k = 0;
    p = L;
    while(p!=NULL && k<i)
    {
        p = p->next;
        k++;
    }
    if(p==NULL)
    {
        printf("删除位置不合理!");
        return ERROR;
    }
    *e = p->data;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return OK;
}

4 线性表应用

4.1 一元多项式

一元多项式的表示:Pn(x) = P0 + P1x +P2x^2 +……+Pnx^n

一元多项式存储:

  • 顺序存储表示:只存储一元多项式各项的系数,每个系数所对应的指数则隐含在存储系数的顺序表下标中。
  • 链式存储表示:存储非零项系数和非零项指数这两项
//链式存储
//一元多项式结点结构定义如下:
typedef struct Polynode {
    int coef; //系数
    int exp;  //指数
    struct Polynode * next;
}Polynode,*Polylist;

//用尾插法建立一元多项式的链表
Polylist PolyCreate {
    Polynode * head, * rear, * s;
    int c, e;
    head = (Polynode *)malloc(sizeof(Polynode));
    rear = head;
    scanf("%d,%d",&c,&e);//输入系数和指数项
    while(c!=0)
    {
        s = (Polynode *)malloc(sizeof(Polynode));
        s->coef = c;
        s->exp = e;
        rear->next = s;
        rear = s;
        scanf("%d,%d",&c,&e);
    }
    rear->next = NULL;
    return(head);
}

//一元多项式的相加运算
void PolyAdd(Polylist polya,Polylist polyb)
{
    Polynode * p, * q, * tail, *temp;
    int sum;
    p = polya->next;
    q = polyb->next;
    tail = polya;
    while(p!=NULL && q!=NULL)
    {
        if(p->exp < q->exp)
        {
            tail->next = p;
            tail = p;
            p=p->next;
        }
        else if(p->exp == q->exp)
        {
            sum = q->coef + q->coef;
            if(sum!=0)
            {
                p->coef=sum;
                tail->next = p;
                tail = p;
                p = p->next;
                temp = q;
                q = q->next;
                free(temp);
            }
            else
            {
                temp = p;
                p = p->next;
                free(temp);
                temp = q;
                q = q->next;
                free(temp);
            }
        }
        else
        {
            tail->next = q;
            tail = q;
            q = q->next;
        }
    }
    if(p!=NULL)
    {
        tail->next = p;
    }
    if(q!=NULL)
    {
        tail->next = q;
    }
}

4.2 就地逆置问题

//相当于头插法
void ReverseList(LinkList L)
{
    Node *p, *q;
    p = L->next;
    L->next = NULL;
    while(p!=NULL)
    {
        q = p->next;
        p->next = L->next;
        L->next = p;
        p = q;
    }
}

5 顺序表和链表的比较

5.1 空间角度

  1. 顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模。适合于线性表长度变化不大,且容易估计长度的情况下。
  2. 存储密度(Storage Density), 是指结点数据本身所占的存储量和整个结点结构所占的存储量之比。若不考虑顺序表中的备用结点空间,则顺序表的存储空间利用率为100%,而单链表的存储空间利用率为50%

结论:当线性表的长度变化不大, 易于事先确定其大小时,为了节约存储空间,宜采用顺序表作为存储结构。

5.2 时间角度

  1. 若线性表的操作主要是进行查找,很少做插入和删除时,宜采用顺序表做存储结构。
  2. 在链表中的任何位置上进行插入和删除,都只需要修改指针。而在顺序表中进行插入和删除,平均要移动表中近一半的结点,尤其是当每个结点的信息量较大时,移动结点的时间开销就相当可观。
  3. 对于频繁进行插入和删除的线性表,宜采用链表做存储结构。 若表的插入和删除主要发生在表的首尾两端,则宜采用尾指针表示的单循环链表。

5.3 语言角度

  1. 对于没有提供指针类型的高级语言,若要采用链表结构,则可以使用光标实现的静态链表。虽然静态链表在存储分配上有不足之处,但它和动态链表一样,具有插入和删除方便的特点。
  2. 对那些具有指针类型的语言,静态链表也有其用武之地。特别是当线性表的长度不变,仅需改变结点之间的相对关系时,静态链表比动态链表可能更方便

6 链式存储方式的比较

链式存储方式的比较

7 实验课题目

7.1 链表删除

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

//单链表的存储结构描述:
typedef struct Node
{
    int data;
    struct Node * next;
}Node,*LinkList;

//初始化单链表:
void CreatFromTail(LinkList L)
{
    struct Node *s;
    struct Node *r;
    int value;
    r = L;
    printf("请输入元素值(输入0表示结束输入):");
    while(1) {
        scanf("%d",&value);
        if(value == 0){
            return;
        }
        s = (struct Node *)malloc(sizeof(struct Node));
        s->data = value;
        r->next = s;
        r = s;
        r->next = NULL;
  }
  return;
}
//删除
void DelList(LinkList L, int e){
    struct Node *pre;
    struct Node *r;
    pre = L;
    r = L->next;
    while(r!=NULL) {
        if(r->data == e) {
        pre->next = r->next;
        }
    r = r->next;
    pre = pre->next;
    }
}

//输出链表
void printList(struct Node *L) {
  struct Node *p;
  p = L->next;
  while(p != NULL) {
    printf("%d ",p->data);
    p = p->next;
  }
  return;
}

int main()
{
  int x;
  struct Node *L;
  L = ( struct Node *)malloc(sizeof(struct Node));
  L->next = NULL;
  CreatFromTail(L);
  printf("请输入要删除的元素:");
  scanf("%d",&x);
  printf("删除前");
  printList(L);
  printf("\n");
  printf("删除后");
  DelList(L,x);
  printList(L);
}

结果如下:
在这里插入图片描述

7.2 链表逆序

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


//单链表的存储结构描述:
typedef struct Node
{
    int data;
    struct Node * next;
}Node,*LinkList;

//初始化单链表:
void CreatFromTail(LinkList L)
{
    struct Node *s;
    struct Node *r;
    int value;
    r = L;
    printf("请输入元素值(输入0表示结束输入):");
    while(1) {
        scanf("%d",&value);
        if(value == 0){
            return;
        }
        s = (struct Node *)malloc(sizeof(struct Node));
        s->data = value;
        r->next = s;
        r = s;
        r->next = NULL;
  }
  return;
}

void ReverseList(LinkList L)
{
    Node *p, *q;
    p = L->next;
    L->next = NULL;
    while(p!=NULL)
    {
        q = p->next;
        p->next = L->next;
        L->next = p;
        p = q;
    }
}

//输出链表
void printList(struct Node *L) {
  struct Node *p;
  p = L->next;
  while(p != NULL) {
    printf("%d ",p->data);
    p = p->next;
  }
  return;
}

int main()
{
  int x;
  struct Node *L;
  L = ( struct Node *)malloc(sizeof(struct Node));
  L->next = NULL;
  CreatFromTail(L);
  printf("逆序前");
  printList(L);
  printf("\n");
  printf("逆序后");
  ReverseList(L);
  printList(L);
}

结果如下:
在这里插入图片描述

7.3 链表合并

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


//单链表的存储结构描述:
typedef struct Node
{
    int data;
    struct Node * next;
}Node,*LinkList;


//初始化单链表:
void CreatFromTail(LinkList L)
{
    struct Node *s;
    struct Node *r;
    int value;
    r = L;
    printf("请输入元素值(输入0表示结束输入):");
    while(1) {
        scanf("%d",&value);
        if(value == 0){
            return;
        }
        s = (struct Node *)malloc(sizeof(struct Node));
        s->data = value;
        r->next = s;
        r = s;
        r->next = NULL;
  }
  return;
}

//输出链表
void printList(struct Node *L) {
  struct Node *p;
  p = L->next;
  while(p != NULL) {
    printf("%d ",p->data);
    p = p->next;
  }
  return;
}

//两个有序的单链表合并
LinkList MergeLinkList(LinkList LA, LinkList LB)
{
    Node *pa, *pb, *pc,*r;
    LinkList LC;
    pa = LA->next;
    pb = LB->next;
    LC = LA;
    LC->next = NULL;
    r = LC;
    while(pa!=NULL&&pb!=NULL)
    {
        if(pa->data<=pb->data)
        {
            r->next = pa;
            r = pa;
            pa = pa->next;
        }
        else
        {
            r->next = pb;
            r = pb;
            pb = pb->next;
        }
    }
    if(pa)
        r->next = pa;
    else
        r->next = pb;
    free(LB);
    //去重
    pc = LC->next;
    while(pc->next!=NULL){
        if(pc->next->data == pc->data)
        {
            pc->next = pc->next->next;
        }
        pc = pc->next;
    }
    return(LC);
}

int main()
{
  struct Node *la;
  struct Node *lb;
  struct Node *lc;
  la = ( struct Node *)malloc(sizeof(struct Node));
  la->next = NULL;
  lb = ( struct Node *)malloc(sizeof(struct Node));
  lb->next = NULL;
  lc = ( struct Node *)malloc(sizeof(struct Node));
  lc->next = NULL;

  CreatFromTail(la);
  CreatFromTail(lb);
  printf("合并前la:");
  printList(la);
  printf(",");
  printf("合并前lb:");
  printList(lb);
  printf("\n");
  printf("合并后lc:");
  lc = MergeLinkList(la,lb);
  printList(lc);
}

结果如下:
在这里插入图片描述

7.4 顺序表合并

#include <stdio.h>
#include <stdlib.h>
#define MAX 20

//顺序表的存储结构描述:
typedef struct
{
	int elem[MAX]; /*线性表占用的数组空间*/
    int last; /*记录线性表中最后一个元素在数组elem[]的位置*/
}SeqList;


//初始化顺序表:
void CreateList(SeqList *L)
{
    int value = 0;
    int i = 0;
    printf("创建顺序表,请输入元素值:");
    while(1)
    {
        scanf("%d",&value);
        if(value == 0)
        {
            break;
        }
        L->elem[i] = value;
        i++;
    }
    L->last = i;
    return;
}

//输出顺序表
void printList(SeqList *L) {
    int i=0;
    while(i<L->last)
    {
        printf("%d ",L->elem[i]);
        i++;
    }
}

void DelList(SeqList *L,int i)
/*
    删除在顺序表第i个位置,用e返回其值
*/
{
    int k;
    if((i<1)||(i>L->last+1))
    {
        printf("删除位置不合法");
        return;
    }
    //e = L->elem[i-1];
    if(L->last >= 20-1)
    {
        printf("表已满,无法插入");
        return;
    }
    for(k = i; k<= L->last; k++)
    {
        L->elem[k-1] = L->elem[k];
    }
    L->last--;
    return;
}

//两个有序的顺序表合并:
void MergeLinkList(SeqList *LA, SeqList *LB,SeqList *LC)
{
    int i=0;
    int j=0;
    int k=0;
    while(i<=LA->last && j<=LB->last)
    {
        if(LA->elem[i]<=LB->elem[j])
        {
            LC->elem[k] = LA->elem[i];
            i++;k++;
        }
        else if(LA->elem[i]>LB->elem[j])
        {
            LC->elem[k] = LB->elem[j];
            j++;k++;
        }
    }
    while(i<LA->last)
    {
        LC->elem[k]=LA->elem[i];
        i++;k++;
    }
    while(j<LB->last)
    {
        LC->elem[k]=LB->elem[j];
        j++;k++;
    }
    LC->last = LA->last+LB->last;
    //去重
    i = 0;
    while(i<LC->last){
        if(LC->elem[i+1]==LC->elem[i])
        {
            DelList(LC,i+1);
        }
        i++;
    }
}

int main()
{
  SeqList *la;
  SeqList *lb;
  SeqList *lc;

  la = (SeqList *)malloc(sizeof(SeqList));
  lb = (SeqList *)malloc(sizeof(SeqList));
  lc = (SeqList *)malloc(sizeof(SeqList));

  CreateList(la);
  CreateList(lb);

  printf("合并前la:");
  printList(la);
  printf(",");
  printf("合并前lb:");
  printList(lb);
  printf("\n");
  printf("合并后lc:");
  MergeLinkList(la,lb,lc);
  printList(lc);
}

结果如下:
在这里插入图片描述

7.5 约瑟夫环

题目描述:
在这里插入图片描述

#include "stdio.h"
#include "stdlib.h"

//链表结构描述:
typedef struct Node{
    int index;
    struct Node *next;
} LinkList;


//初始化线性表
LinkList* CreateList(LinkList *L,int n){

    LinkList *p;
    LinkList *r;

    L=(LinkList*)malloc(sizeof(struct Node));
    L->next=NULL;
    r=L;
    for (int i=1; i<=n; i++)
    {
        p=(LinkList*)malloc(sizeof(struct Node));
        p->index=i;
        r->next=p;
        r=p;
    }
    r->next=L->next;
    L = L->next;
    return L;
}

//删除
void DelList(LinkList *L,int n){
    LinkList *q;
    while(L!=L->next)
    {
        for (int i = 2; i <n; i++)
        {
            L=L->next;
        }
        q=L->next;
        L->next=L->next->next;
        free(q); //释放节点
        L=L->next;
    }
    printf("最后剩余的猴子是:%d",L->index);
}

int main(){

    LinkList *L;
    LinkList *Head=NULL;
    LinkList *Circle;

    int n,m,start;
    printf("猴子个数:");
    scanf("%d",&n);
    printf("设置M为:");
    scanf("%d",&m);
    Head = CreateList(L,n);
    DelList(Head,m);
    return 0;
}

结果如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值