单项链表基本函数以及链表合并

原创 2013年12月05日 09:22:14
#include <stdlib.h>
#include <stdio.h>
#define LEN sizeof(DAT)
#define TRUE 1
#define FALSE -1
#define NULL 0

typedef struct LNode{

 int data;
 struct LNode *next;

}DAT;

void InitList(DAT *head)//创建空表

{
 head = (DAT *)malloc(LEN);
 if(!head)
 {printf("\n--链表创建失败--\n");exit(FALSE);}
 head ->next = NULL;
}

DAT *creatList(DAT *head)//数据录入

{
 DAT *p1,*p2;
 char ch;
 int n = 1;
 head = (DAT *)malloc(LEN);
 p1 = p2 = (DAT *)malloc(LEN);
 if(p1 != NULL)
 {
     printf("\n请输入数据:\n");
     scanf("%d",&p1->data);//p1需要存储数据,每一次存储都需要申请空间

  head -> next = p1;//注意:本程序的头结点不存储数据,因为ClearList函数和destroyList函数无法区分实现
                    //所以ListTraverse输出函数也是从头结点的下一个才开始输出的!
  //p2 = p1;为什么这步可以省略呢?就是因为p1,p2在申请空间的时候被赋予的地址是一致的!

  printf("\n继续录入(y/any other keys to exit)?\n");
  getchar();
  scanf("%c",&ch);
  while(ch == 'Y'||ch == 'y')
  {
   printf("\n请输入数据:\n");
   p1 = (DAT *)malloc(LEN);
   if(p1 != NULL)
            scanf("%d",&p1->data);
   p2 -> next = p1;
   p2 = p1;
   printf("\n继续录入(y/any other keys to exit)?\n");
   getchar();
         scanf("%c",&ch);
  }
  p2 -> next = NULL;//p2作为连接新建节点的指针,如果next为空,那自然是结束了录入
  printf("\n--录入结束--\n");
 }

 return head;
}


 int ClearList(DAT *head) //保留头结点,其余节点数据清空
 {
   if(head == NULL)
   {
    printf("\n--表不存在--\n");
    return FALSE;
   }
   DAT *p,*q;

   p = head -> next;

   while(p)
   {
     q=p->next;//用声明的另一个指针q来记录p的下一节点的位置

  printf("\n--已删除表中数据:%d--\n",p -> data);

  free(p);

  p=q;//结合q = p -> next,此语句的作用即是让p往后移动,从而实现逐个清空数据的目的

   }//直至p为空的时候便是结束了循环,清空结束

   head -> next = NULL; //数据清空之后头结点的指针域为空
   return TRUE;
 }

 DAT *destroyList(DAT *head)//与清空链表函数不同,销毁需要把头结点也一同清除,清楚后将无法再录入数据
 {
     if(head == NULL)
  {
    printf("\n--表不存在,销毁无效--\n");
    exit(FALSE);
  }
     DAT *p;
  p = head;
     while(head)
  {

   p = head -> next;
   free(head);//第一次循环的时候清除了头结点
   head = p;
  }
  printf("\n--链表销毁结束--\n");
  return head;
 }

 int ListLength(DAT *head)

{
 DAT *p;
 int i = 0;
 p = head -> next;
 while(p)
 {
  i++;
  p = p -> next;
 }
 printf("\n--链表长度为:%d--\n",i);
 return i;
}

void ListTraverse(DAT *head)//输出函数

{
 DAT *p = head -> next;
 DAT *q = p;//位序输出遍历需要
 int n = 0;
 int length = ListLength(head);
 if(p)
 {
  printf("\n位序 | ");
   
  for(n = 1;n <= length;n++)
  {

      if(q -> data <10)
      printf("%d ",n);
      else if(q -> data <100)
      printf("%2d ",n);
      else 
      printf("%3d ",n);
      q = q -> next;
  }
  
  printf("\n------------------------------------\n");
  printf("数据 | ");
  do
  {
   printf("%d ",p -> data);
   p = p -> next;
  }
  while(p);
 }
 printf("\n");
}

 

int GetElem(DAT *head,int i,int e)

{
  int n = 1;
  DAT *p;
  p = head ->next;
     while(p && n < i )//当p不为空且初始位序小于查找位序的时候
     {
   p = p -> next;//指针后移,直至与查找位序相等为止推出循环
   n++;
  }
  if(!p || n > i)
  {printf("\n--找不到该位序--\n");return FALSE;}
  e = p -> data;
  return e;
}

int LocateElem(DAT *head,int e)//查找e的位序,并将其位序返回

{
 DAT *p;
 int i = 1;
 printf("\n请输入你要查找的数据:\n");
 scanf("%d",&e);
    p = head -> next;
 while(p)
 {

  if(p -> data == e)
  {

   printf("\n--%d的位序为:%d--\n",e,i);
   return i;
  }
  else
  p = p -> next;
  i++;
 }

 printf("\n--找不到该元素--\n"); return 0;

}

int PirrorElem(DAT *head,int cur_e,int pre_e)//查找元素的前驱

{
 printf("\n请输入表中数据,系统将会返回其的前驱:\n");
 scanf("%d",&cur_e);
 if(head == NULL)
 {
  printf("\n--表不存在--\n");
  return FALSE;
 }

 DAT *p,*q;
 q = head -> next;//q指向第一个节点
 while(p)
 {
  p = q -> next;//p指向q的下一节点

  if( q -> data == cur_e)//cur_e为第一个元素的时候,提示错误
  {
   printf("\n--表中第一个元素是没有前驱的,无法查找--\n");
            return FALSE;
  }
        if(p -> data == cur_e)//如果p指针找到了cur_e,就用q返回前驱
  {
   pre_e = q -> data;
   printf("\n--%d的前驱是:%d--\n",cur_e,pre_e);
   return pre_e;
  }
  else
  {
   if( p -> next != NULL)
   q = p;//p,q指针相连,q后移也会带动p的后移

   else// p遍历结束达到NULL的时候即是没有找到输入的数据,提示错误
   {
       printf("\n--表中无此数据--\n");
             return FALSE;
   }

  }
 }

}

int NextElem(DAT *head,int cur_e,int next_e)//查找元素的后继
{
 DAT *p,*q;
 printf("\n请输入数据,系统将会返回其的后继:\n");
 scanf("%d",&cur_e);
 p = head -> next;
 while(p)
 {
  q = p -> next;
  if( p -> data == cur_e && p -> next != NULL)//p没有下一节点的话,也就没有后继之说了
  {
   next_e = q -> data;
   printf("\n-%d的后继为:%d--\n",cur_e,next_e);
   return next_e;
  }

  if( p -> data != cur_e)
  {
   p = q;//p -> next 不为空的时候,p,q后移遍历

   if( p -> next == NULL && p -> data == cur_e )//判断是否有后继
   {
    printf("\n--末位的数据是没有后继的,无法查找--\n");
    return FALSE;
   }
   if( p -> next == NULL && p ->data != cur_e)//判断时候存在cur_e
   {
    printf("\n--表中不存在该元素--\n");
    return FALSE;
   }
  }
 }

}

DAT *ListInsert(DAT *head,int i,int e)//按位序i插入特定元素e
//定义结构体指针函数,用于返回结构体指针head
{
 printf("\n请输入插入的位序和元素\n");
 scanf("%d%d",&i,&e);
 DAT *p = head;//和下面n = 0相对应,head无数据
 DAT *q;
 int n = 0;
 while(p != NULL && n < i-1)//找到i的前一个节点
 {
  p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
  n++;//n = 1
 }//出循环时n=i-1,p也就指向了i的前一位序

 if(p == NULL || n > i-1)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
 {
  printf("\n--位序错误,插入失败--\n");
  return head;
 }

    q = (DAT *)malloc(LEN);//新节点空间申请
 q -> data = e;//新节点赋值
 q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
 //如果是表尾插入的话,q -> next == NULL
 p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
 printf("\n--%d已添加到表中第%d位序--\n",e,i);
 return head;//返回头指针,方便打印链表
}

DAT *ListInsert_last(DAT *head,int e)//表尾插入函数

//定义结构体指针函数,用于返回结构体指针head
{
 int leng = ListLength(head);
 DAT *p = head;//和下面n = 0相对应,head无数据
 DAT *q;
 int n = 0;
 while(p != NULL && n < leng)//找到尾节点,在尾节点的后一节点添加数据
 {
  p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
  n++;//n = 1
 }//出循环时n=leng,p也就指向了表尾

 if(p == NULL || n > leng)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
 {
  printf("\n--位序错误,插入失败--\n");
  return head;
 }

    q = (DAT *)malloc(LEN);//新节点空间申请
 q -> data = e;//新节点赋值
 q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
 //如果是表尾插入的话,q -> next == NULL
 p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
 printf("\n--%d已添加到表尾--\n",e);
 return head;//返回头指针,方便打印链表
}


DAT *ListDelete(DAT *head,int i,int e)

{
 printf("\n请输入你要删除的位序:\n");
 scanf("%d",&i);
    DAT *p = head;
 DAT *q;
 int n = 0;
 while(p -> next != NULL && n < i - 1)//循环是为了找到要删除的节点的前驱,即p指向删除节点的上一个节点
 {
  p = p -> next; 
  n++;
 }
 if(p -> next == NULL || n > i -1)//i过大或过小的时候报错退出(要删除的节点不能为空)
 {
  printf("\n--位序错误,删除失败--\n");
  return head;
 }
 q = p -> next;//q指向p的下一节点
 p -> next = q -> next;//将p的下一节点绕到q的下一节点上去,完成对q节点的孤立,将q节点删除
 e = q -> data;//用e返回被删除的节点上的数据
 free(q);
 printf("\n--表中第%d位序上的数据:%d已被删除--\n",i,e);
 return head;

}



#include "E.h"

void main()

{

    //DAT *head;
 //int i,e;
 //int cur_e;
 //int pre_e;
 //int next_e;
 //开始测试函数
 //InitList(head);//创建空表
 //head = creatList(head);//输入数据
    //ListTraverse(head);//输出数据
 //ListLength(head);//输出链表长度
 //ClearList(head);//清空数据
 //ListTraverse(head);//输出清空效果
    //destroyList(head);
 //ListTraverse(head);
 
    //printf("\n请输入你要查找的位序:\n");
 //scanf("%d",&i);
 //e = GetElem(head,i,e);
 //if(e != FALSE)
    //printf("\n--位序%d上的数据为:%d--\n",i,e);
 //PirrorElem(head,cur_e,pre_e);
 //NextElem(head,cur_e,next_e);
 //head = ListInsert(head,i,e);
 //head = ListDelete(head,i,e);
 //ListTraverse(head);*/

 //用自建函数合并两个不同数据的链表
 DAT *L1 = NULL;
 DAT *L2 = NULL;
    DAT *L3 = NULL;
 DAT *p1 = NULL;
 DAT *p2 = NULL;
 DAT *p3 = NULL;
 DAT *p4 = NULL;
 DAT *p5 = NULL;
 int n = 0;
 int m = 0;
 int leng1;
 int leng2;
 int leng3;
 int i = 0,j = 0,k = 0;
    InitList(L1);
 InitList(L2);
 L1 = creatList(L1);
 p1 = L1;
 ListTraverse(L1);
 L2 = creatList(L1);//录入两个链表数据
 p2 = L2;
 ListTraverse(L2);
leng1 = ListLength(L1);
 leng2 = ListLength(L2);//链表长度获取
 L3 = (DAT *)malloc(sizeof(DAT));//第三链表的建立,用于存储表一和表二中不重复的数据
 p3 = p4 = (DAT *)malloc(sizeof(DAT));
 if(leng1 >= leng2)
 {
  for(i = 0;i < leng2;i++)
  {  
   if(p2 -> next != NULL)
   {p2 = p2 -> next;}
   
   for(j = 0; j < leng1;j++)
   {
    
                if(p1 -> next != NULL)
    {  
     p1 = p1 -> next;
     
    }
    else//p1 -> next ==NULL的时候
    {
     p1 = L1 -> next;//重置p1回到L1的第一个节点
    }
    if(p2 -> data != p1 -> data)//表三数据链表的录入
    { printf("\n--%d--\n",p2->data);
        printf("\n-|%d|-\n",p1->data);
     m++;
     printf("\nm = %d\n",m);
     if(m == leng1)//将表二的一个数对比表一中所有的数,如果都不一样则将这个数插入表三
     {
         p3 -> data = p2 -> data;
      if(p3 -> data != NULL)
      {
             n++;
             if(n == 1)
             L3 -> next = p3;
                            else
             p4 -> next = p3;
             p4 = p3;

             p3 = (DAT *)malloc(sizeof(DAT));
      }
      p4 -> next = NULL;
      m = 0;//重置m
           
     }
    }
   }

 if(m <leng1)//m小于leng1说明有数重复,为了下一个数的比较可以顺利进行,标志m也要重置
      m=0;
  }

//因为是很久以前的数据结构作业,源文件已经找不到了,还好QQ空间当初留有图片(下面的图片衔接上一部分)



//少了一个花括号

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

单项链表和双向环链表

  • 2011-03-27 18:57
  • 12KB
  • 下载

Java实现两个有序的单项链表的合并

无意中看到一道题,如下: 现有两个有序(升序)的单向链表,请编写程序将这两个链表合并成一个,并确保合并后的链表也是升序的 单向升序链表定义: public class ListNode {  int ...

洛谷1972 [SDOI2009]HH的项链(链表+树状数组)

题目描述 HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长...

关于c语言编写 单项链表 的创建、插入、修改、删除、显示、退出 的程序案例

#include #include #define OK 1 #define ERROR -1 /*******************定义节点结构*****************/ type...

单项链表得操作

初学者单项链表借鉴

内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)