C语言基础-链表

参考清华大学软件学院 谌卫军   《c语言程序设计》课件

1、链表

1.1 链表的基本概念

链表中的每一个元素称为一个“结点”,每个结点都应该包括两部分:一为用户需要使用的实际数据;二为下一个结点的起始地址。另外,链表还有一个头指针head,指向链表的首结点。


定义如下的结构体类型

struct Train_tag
{
  char Num[8];
  char Name[10];
  int Weight;
  char From[20];
  char To[20];  // 数据域
  struct Train_tag *next; // 指针域
}

2、对链表的操作

2.1、创建动态链表

例:创建一个链表,并输入每一个结点的各种描述信息(集装箱编号、货物名称、货物重量、发货地点、到货时间等),

直到用户输入的货物重量等于0,表示链表结束。

struct Train_tag
{
  char Num[8];  //集装箱编号
  char Name[10];//货物名称
  int Weight;   //货物重量
  char From[20];//发货地点
  char To[20];  //到货地点
  struct Train_tag *next;//指向下一结点
};
struct Train_tag *head,*p,*q;

创建链表的过程可归纳为如下三个步骤:

①只要用户输入的Weight不为0,就要构建链表。基本思路是将一个一个的结点添加至链表中。首先用指针p来申请一个结构体变量的内存空间,并且装入用户输入的各种描述信息,然后将指针q和head都指向它,如下图:


②后续结点的创建:如果用户输入的Weight又不为0,就要构建链表的第二个结点。首先用指针p来申请一个结构体变量的内存空间,并且装入用户输入的各种描述信息,然后要执行q->next=p,把第一个结点的next指针去指向它,从而建立两个结点之间的链接关系。最后再把q指向新的结点。如下图:


第三个结点加入链表的过程:


③链表创建过程的结束:如果用户输入的Weight等于0,意味着链表创建过程的结束,此时指针q所指向的就是链表的最后一个结点,所以要把该结点的next指针赋值为NULL,即执行q->next=NULL,表示这里已是链尾,后面不会再连结点。如下图:


void Create()
{
  int Weight;
  head = p = q = NULL;
  while(1)
  {
    printf("输入货物重量:");
    scanf("%d",&Weight);
    if(Weight <= 0) break;
    p = malloc(sizeof(struct Train_tag));
    p->Weight = Weight;
    //输入该结点的其它信息;
    if(head == NULL) head = p;//新建的是首结点
    else q->next = p;  // 不是首结点
    q = p;    // q指向当前尾结点
  }
  if(head != NULL) q->next = NULL;
}

2.2、访问链表

在创建好一个链表之后,可以依次地访问该链表当中的各个结点的数据。

void Display(struct Train_tag *head)
{
  struct Train_tag *p;
  p = head;
  while(p != NULL)
  {
    printf("%s,%s,%d,%s,%s\n",p->Num;p->Name,p->Weight,p->From,p->To);
    p = p->next;
  }
}

2.3、删除链表结点

情形一、待删除的是首结点


情形二、待删除的不是首结点


void Delete(struct Train_tag *head)
{
  struct Train_tag *p,*q;
  if(head == NULL) {printf("空链表");return;}
  p = head;
  while((p!=NULL) && strcmp(p->To,"湖南"))
  {
    q = p;
    p = p->next;//把指针p往后移动一个结点
  }

  if((p != NULL) && !strcmp(p->To,"湖南"))
  {
    if(p == head)
      head = p->next;//删除的是首结点
    else
      q->next = p->next;//删除的是中间结点
  }
}

2.4、插入链表结点

原则:

①插入操作不应破坏原有链接关系;

②需要插入的这个结点应该把它放在合适的位置上,即有一个插入位置的查找过程。

定义:

struct Train_tag *head;//头指针
struct Train_tag *p;   //链表当前结点
struct Train_tag *q;   //链表上一结点
struct Train_tag *pNode;//待插入的结点

第一种情况:链表为空,即head=NULL

待插入的pNode结点就是链表中的第一个结点,head = pNode;

第二种情况:若pNode->Weight<=head->Weight,则

pNode->next = head;
head = pNode;

第三种情况:pNode结点插入在链表的中间,设指针q和指针p分别指向相邻的两个结点,q在前p在后。

首先让q=head,让p=head->next,然后让它们顺序往后移动,每次移动一个结点。当满足q->Weight<pNode->Weight<=p->Weight时,pNode就插在q与p之间。

//移动指针
q = p;
p = p->next;

//插入结点
pNode->next = p;
q->next = pNode;
void Insert(struct Train_tag *pNode)
{
  struct Train_tag *p,*q;
  // 第一种情形,链表为空
  if(head == NULL)
  {
    head = pNode;
    return;
  }
  // 第二种情形,新结点的Weight小于等于首结点
  if(pNode->Weight <= head->Weight)
  {
    pNode->next = head;
    head = pNode;
    return;
  }
  // 第三种情形,循环地查找正确的插入位置
  q = head;
  p = head->next;
  while(p != NULL)
  {
    if(pNode->Weight <= p->Weight)
      break;
    else
    {
      q = p;
      p = p->next;
    }
  }
  // 将pNode结点插入在正确的位置(q和p之间)
  pNode->next = p;
  q->next = pNode;
}

2.5、链表的释放

void Destroy(struct Train_tag *head)
{
  struct Train_tag *p,*q;
  p = head;
  while(p != NULL)
  {
    q = p;
    p = p->next;
    free(q);
  }
}
// head = NULL;

3、环形链表

定义一个名为STUDENT的结构体类型

struct STUDENT
{
  int number;    //表示同学的编号
  struct STUDENT *next;//指向下一位同学
}
struct STUDENT *head,*tail,*p,*prev;
int n,m,i,j;

模块1:输入学生的个数n和不吉利的数字m,然后验证它们的有效性;

模块2:创建一个环形链表,模拟众同学围成一圈的情形;

模块3:进入循环淘汰环节,模拟从1到m报数,让n-1个同学逐一退出圈子的过程;

模块4:输出结果。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值