数据结构之线性表(单链表)

注意:这篇博客是我转别人的,当中有点小缺陷;在"while(p&&j<i)"元素定位中,希望大家参考。
1. 线性链表
  
    线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单 元可以是连续 的,也可以是不连续的)。这些数据元素可以存在内存未被占用的任意位置。
   它包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指 针域。指针域 中存储的信息称为指针或链。
   由于此链表的每个结点中只包含一个指针域,故又称为线性链表或单链表。
   对于线性表来说,总得有个头有个尾,链表也不例外。我们把链表中第一个结点的存储位置 叫做头指 针,那么整个链表的存取就必须是从头指针开始进行的。之后的每个结点,其实就是上 一个后 指针指向的 位置。最后一个结点,意味着后继不再存在,所以,规定线性链表的最后一个 结点指针为“空”(通常为 NULL)。 

   线性表的单链表存储结构,如下所示。
  1. typedef struct Node
  2. {
  3.      ElemType data;
  4.      struct Node *next;
  5. }Node, LinkList;

2. 线性表的操作

   获取链表第i个数据的算法思路:

  1)声明一个结点p指向链表第一个结点,初始化j1开始;

  2)j<i< span="" style="word-wrap: break-word;">时,就遍历链表,p的指针向后移动,不断指向下一个结点,j累加1

  3)若到链表末尾p为空,则说明第i个元素不存在;

  4)否则查找成功,返回结点p的数据。


  单链表第i个数据插入结点的算法思路:

  

  1)声明一个结点p指向链表的第一个结点,初始化j1开始;

  2)j<i< span="" style="word-wrap: break-word;">时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1

  3)若到链表末尾p为空,则说明第i个元素不存在;

  4)否则查找成功,在系统中生成一个空结点s

  5)将数据元素e赋值给s->data

  6)单链表的插入标准语句s->next = p->nextp->next = s

  7)返回成功。


  单链表第i个数据删除结点的算法思路:

  

  1)声明一个结点p指向单链表的第一个结点,初始化j1开始;

  2)j<i< span="" style="word-wrap: break-word;">时,就遍历链表,让p指针向后移动,不断指向下一个结点,j累加1

  3)若到链表末尾p为空,则说明第i个元素不存在;

  4)否则查找成功,将欲删除的结点p->next赋值给q

  5)单链表的删除标准语句p->next = q->next

  6)q结点中的数据赋值给e,作为返回;

  7)释放q结点。


  单链表的整表创建的算法思路:

  

  1)声明一个结点p和计数器变量i

  2)初始化一空链表L

  3)L的头结点的指针指向NULL,即建立一个带头结点的单链表;

  4)循环

生成一新结点赋值给p

随机生成一数字赋值给p的数据域p->data

p插入到头结点域前一新结点之间。


  单链表的整表删除的算法思路如下:

  

  1)声明一结点pq

  2)将第一个结点赋值给p

  3)循环:

将下一个结点赋值给q

释放p

q赋值给p


3. 线性表操作的C实现

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

  3. #define OK 0
  4. #define ERROR 1

  5. //typedef ElemType int;
  6. #define ElemType int
  7. typedef struct Node
  8. {
  9.     ElemType data;
  10.     struct Node *next;
  11. }Node, *LinkList;

  12. /* 函数功能:获取链表第i个数据
  13.  * 操作结果:用e返回L中第i个数据元素的值
  14.  * 返回值:
  15.  *         ERROR:i值不合法
  16.  *         OK     :操作成功
  17.  *
  18.  * 最坏时间复杂度为O(n)
  19. */
  20. int GetElem(LinkList L, int i, ElemType *e)
  21. {
  22.     if( i <= 0)
  23.     {
  24.         fprintf(stderr, "i should more 1 and less LinkLength(L).\n");
  25.         return ERROR;
  26.     }
  27.     LinkList p = L->next;            //声明一结点p
  28.     int j = 1;                        //j为计数器

  29.     while(< i && p != NULL)        //p不为空且计数器j还没有等于i时,循环继续
  30.     {
  31.         p = p->next;
  32.         j++;
  33.     }

  34.     if(!|| j > i)                    //第i个元素不存在
  35.     {
  36.         return ERROR;
  37.     }

  38.     *= p->data;

  39.     return OK;
  40. }


  41. /* 函数名称: ListInsert
  42.  * 函数功能: 在链表的第i个位置之前插入数据元素e
  43.  * 返回值:
  44.  *        ERROR: i不合法
  45.  *        OK : 插入成功
  46.  * 
  47.  * 注意:参数L为指针的指针
  48. */

  49. int LinkInsert(LinkList *L, int i, ElemType e)
  50. {
  51.     if( i <= 0)
  52.     {
  53.         fprintf(stderr, "i<=0不合法.\n");
  54.         return ERROR;
  55.     }

  56.     LinkList p;
  57.     p = *L;
  58.     int j = 1;

  59.     while(< i && p != NULL)            //寻找第i个结点
  60.     {
  61.         p = p->next;
  62.         ++j;
  63.     }

  64.     if(!|| j > i)                        //第i个结点不存在
  65.     {
  66.         return ERROR;
  67.     }

  68.     LinkList temp = (LinkList)malloc(sizeof(struct Node));
  69.     if(!temp)
  70.     {
  71.         fprintf(stderr, "malloc() error.\n");
  72.         return ERROR;
  73.     }

  74.     temp->data = e;

  75.     temp->next = p->next;
  76.     p->next = temp;

  77.     return OK;
  78. }

  79. /* 函数名称: ListDelete
  80.  * 函数功能: 删除L中的第i个元素,并用e返回其值
  81.  * 返回值:
  82.  *        ERROR: i不合法
  83.  *        OK : 删除成功
  84.  *
  85.  * 最坏时间复杂度为O(n)
  86. */
  87. int ListDelete(LinkList *L, int i, ElemType *e)
  88. {
  89.     if(<= 0)
  90.     {
  91.         fprintf(stderr, "i <= 0不合法.\n");
  92.         return ERROR;
  93.     }

  94.     LinkList p,q;
  95.     p = *L;
  96.     int j = 1; 

  97.     while(< i && p->next != NULL)        //遍历寻找第i个结点
  98.     {
  99.         p = p->next;
  100.         ++j;
  101.     }

  102.     if(p->next == NULL || j > i)
  103.     {
  104.         return ERROR;
  105.     }

  106.     q = p->next;
  107.     p->next = q->next;
  108.     *= q->data;

  109.     free(q);
  110.     
  111.     return OK;
  112. }

  113. /* 函数名称: CreateList
  114.  * 函数功能: 随机产生n个元素的值,建立带头结点的单链表L(头插法)
  115.  * 返回值:
  116.  *        ERROR: malloc() error
  117.  *        OK : 创建成功
  118.  *
  119.  */
  120. int CreateList(LinkList *L, int n)
  121. {
  122.     LinkList p;
  123.     int i = 1;
  124.     srand(time(0));                                    //初始化随机数种子

  125.     *= (LinkList)malloc(sizeof(struct Node));        //先建立一个带头结点的单链表
  126.     if(*== NULL)
  127.     {
  128.         fprintf(stderr, "malloc() error.\n");
  129.         return ERROR;
  130.     }
  131.     (*L)->next = NULL;

  132.     while(<= n)
  133.     {
  134.         p = (LinkList)malloc(sizeof(struct Node));
  135.         if( p == NULL)
  136.         {
  137.             fprintf(stderr, "malloc() error.\n");
  138.             return ERROR;
  139.         }
  140.         p->data = rand() % 100 + 1;
  141.         p->next = (*L)->next;
  142.         (*L)->next = p;                                    //插入到表头
  143.         
  144.         i++;
  145.     }
  146.     /*
  147.     //尾插法
  148.     LinkList r;
  149.     r = *L;                                                //r为指向尾部的结点
  150.     for(= 0; i < n; i++)
  151.     {
  152.         p = (LinkList)malloc(sizeof(struct Node));        //生成新结点
  153.         p->data = rand() % 100 + 1;
  154.         r->next = p;                                    //将表尾终端结点的指针指向新结点
  155.         r = p;                                            //将当前的新结点定义为表尾部结点
  156.     }
  157.     r->next = NULL;                                        //表示当前链表结束
  158.     */
  159.     return OK;
  160. }

  161. /* 函数名称: ClearList
  162.  * 函数功能: 单链表删除
  163. */
  164. int ClearList(LinkList *L)
  165. {
  166.     if(*== NULL)
  167.     {
  168.         return ERROR;
  169.     }

  170.     LinkList q, p;
  171.     p = (*L)->next;        //p指向第一个结点

  172.     while(p)            //没有到表尾部
  173.     {
  174.         q = p->next;    //注意哦
  175.         free(p);
  176.         p = q;
  177.     }

  178.     (*L)->next = NULL;    //头结点指针域为空

  179.     return OK;
  180. }

  181. int printList(LinkList L)
  182. {
  183.     LinkList p;
  184.     p = L->next;
  185.     if(== NULL)
  186.     {
  187.         printf("链表为空.\n");
  188.         return ERROR;
  189.     }
  190.     while(p)
  191.     {
  192.         printf("%d ", p->data);
  193.         p = p->next;
  194.     }
  195.     printf("\n");

  196.     return OK;
  197. }

  198. int main(int argc, char **argv)
  199. {
  200.     LinkList L;
  201.     
  202.     printf("创建的新链表为:\n");
  203.     CreateList(&L, 5);
  204.     printList(L);
  205.     
  206.     printf("在第3个位置之前插入元素10后结果为:\n");
  207.     LinkInsert(&L, 3, 10);
  208.     printList(L);

  209.     int e;
  210.     GetElem(L, 3, &e);     
  211.     printf("链表第3个位置的元素为: %d\n", e);
  212.     
  213.     printf("删除第3个位置的元素后结果为:\n");
  214.     ListDelete(&L, 3, &e);
  215.     printList(L);
  216.     
  217.     printf("清空链表:\n");
  218.     ClearList(&L);
  219.     printList(L);
  220.     
  221.     return 0;
  222. }
    运行环境:RedHat
   编译工具:Gcc
   
   运行结果如下所示:




    参考:严蔚敏老师之《数据结构》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值