单链表

学习数据结构已经很久了,现在复习一下,欢迎各位批评指正

本文主要是实现单链表的建立/测长/排序/插入/删除功能,首先定义结构体如下:

typedef struct student
{
  int data;
  struct student *next;
}node;

单链表的建立

node *create()
{
  node *head,*p,*s;
  int x,cycle=1;
  head=(node *)malloc(sizeof(node));
  p=head;
  printf(" please input the data:\n");
  while(cycle)
  {
   scanf("%d",&x);
   if(x!=0)
   {
     s=(node *)malloc(sizeof(node));
     s->data=x;
     p->next=s;
     p=s;
   }
   else 
   {
       cycle=0;
   }
  }
  head=head->next;
  p->next=NULL;
  return(head);
}

注意我这里是以0为输入结束标志,你们可以进行改动

单链表的测长

int length(node *head)
{
 int num=0;
 node *p;
 p=head;
 while(p)
 {
   num++;
   p=p->next;
 }
 return num;
}

单链表的排序

使用冒泡排序算法进行升序排序;冒泡排序就是依次比较两个相邻的数,将小数放前面,大的放后面。

  1. 在第一趟:首先第1个数和第2个数,小的放前,大的放后。然后比较第2个和第3个数,小的放前,大的放后。如此继续,直到比较最后两个数。第一趟结束,将最大的数放到了最后面
  2. 第二趟:仍从第一对数进行比较,小的放前,大的放后,直到比较到倒数第二个数(倒数第一的位置上已经是最大的)。第二趟结束,将第二大的数放在了倒数第二的位置上。
  3. 总共经过n-1趟,完成排序。因为当只有一个元素时,该元素一定是最小的。
node *sort(node *head)
{
  node *p;
  int n;
  n=length(head);
  int temp;
  if(head==NULL||head->next==NULL)
  {
    return head;
  }
  for(int j=1;j<n;j++)
  {
    p=head;
    for(int i=0;i<n-j;i++)
    {
      if(p->data>p->next->data)
      {
        temp=p->data;
        p->data=p->next->data;
        p->next->data=temp;
      }
      p=p->next;
    }
  }
 return head;
}

单链表的插入

单链表的插入有三种情况:

  1. 插入在头结点之前,即p1的前面
    这里写图片描述
    此时进行的操作是 p0->next=p1; head=p0;
  2. 插入中间结点,即将p0插入到p2与p1的中间
    这里写图片描述
    此时进行的操作是 p0->next=p1;p2->next=p0;(这里不能调换顺序)
  3. 插入尾结点,即p1的后面
    这里写图片描述
    此时进行的操作是 p0->next=NULL;p1->next=p0;
node *insert(node *head,int num)   //按序插入
{
  node *p0,*p1,*p2;
  p1=head;
  p0=(node *)malloc(sizeof(node));
  p0->data=num;
  while(p0->data>p1->data&&p1->next!=NULL)
  {
    p2=p1;
    p1=p1->next;
  }
  if(p0->data<=p1->data)
  {
    if(head==p1)  //情况1
    {
     p0->next=p1;
     head=p0;   
    }
    else      //情况2
    {
      p0->next=p1;
      p2->next=p0;
    }
  }
  else    //情况3
  {
    p0->next=NULL;
    p1->next=p0;
  }
  return head;
}

单链表的删除

单链表的删除有两种情况:

  1. 删除头结点,即p1
    这里写图片描述
    此时进行的操作为:head=p1->next;free(p1);
  2. 删除中间结点(包含尾结点),即p1
    这里写图片描述
    此时进行的操作为:p2->next=p1->next;free(p1);
node *del(node *head,int num) //删除元素num
{
    node *p1,*p2;
    p1=head;
    while(num!=p1->data&&p1->next!=NULL)
    {
      p2=p1;
      p1=p1->next;
    }
    if(num==p1->data)
    {
      if(p1==head)   //情况1
      {
          head=p1->next;
          free(p1);
      }
      else    //情况2
      {
        p2->next=p1->next;
        free(p1);
      }
    }
    else
    {
     printf("\n %d could not been found",num);
    }
    return head;
}

单链表的打印

void print(node *head)
{
   node *p;
   int n;
   n=length(head);
   printf("\nNow,these %d records are:\n",n);
   p=head;
   while(p)
   {
    printf("%d\n",p->data);
    p=p->next;
   }
}

单链表的逆置

例如:在第一次逆置中,将p1跟p2之间的方向进行逆转
执行的操作是 p3=p2->next; p2->next=p1; p1=p2;p2=p3;
其中p3用来记录p2后面的元素;p2->next=p1实现p2跟p1逆置;如下所示

这里写图片描述
p1=p2;p2=p3;是选择下一次进行逆置的指针,此时状态如下
这里写图片描述

如此下去,最终p1指向最后一个元素,p2=NULL;此时只需执行操作head->next=NULL;head=p1;

node *reverse(node *head)  
{  
    node *p1, *p2, *p3;  
    if(NULL==head||NULL==head->next)  //当链表为空或者只有一个元素时
    {
      return head;
    }
    p1=head;      
    p2=p1->next;
    while(p2)    //每相邻的两个元素进行逆置
    {
     p3=p2->next;
     p2->next=p1;
     p1=p2;
     p2=p3;
    }
    head->next=NULL;
    head=p1;  
    return head;
}  

头文件

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<conio.h>   //声明控制台输入输出所需函数的头文件
using namespace std;

主函数

int main()
{
  node *head;
  int len;
  head=create();
  len=length(head);
  printf("the number of records is: %d",len);
  printf("\n排序后:\n");
  head=sort(head);
  print(head);
  printf("删除元素3后:\n");
  head=del(head,3);
  print(head);
  printf("插入元素5后:\n");
  head=insert(head,5);
  print(head);
  printf("进行逆置后:\n");
  head=reverse(head);
  print(head);
  return 0;
}

结果图

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值