zoukankan      html  css  js  c++  java
  • c语言数据结构,静态链表,结构体数组

    众所周知,我的博客是写给自己看的。

    在敲"严版"数据结构的静态数组时遇到的一些问题,并给予了改进,在此记录一下

    前言:

    没有实现教材上那个(A-B)v(B-A)的例子,实现了增加、删除等。总体上把握了静态数组的基本思想后实现这些例子都是很简单的。作了一点小改进

    正文:

         改进:

    把一个静态数组分为两条形式上的链表,一条是已分配空间,一条是未分配的空间。从尾部开始,链表的头标记为arr[10].cur遍历可获得A-B-C-D,arr[10].data为已分配结点的数量;arr[0].cur是未分配空间的头标记,arr[0].data为未分配结点的数量;插入一个结点就把可用空间的结点通过改变cur来实现连接,删除也是同样的思想。

    静态数组,其实就是顺序表。依靠结构体成员,像链表一样把不同的空间连起来,只不过把指针类型的成员变量用int类型代替。

    下面是结构体:

    1 int LISTSIZE = 100;
    2 typedef int ElemType;
    3 typedef struct SLinkList {
    4   ElemType data;
    5   int cur;
    6 } SLinkList;

    // 不建议
    1 int LISTSIZE = 100; 2 typedef int ElemType; 3 typedef struct SLinkList { 4 ElemType data; 5 int cur; 6 } SLinkList[LISTSIZE];

    1)、设置一个全局变量LISTSIZE代替书上的宏变量,方便在数组空间不够用的情况下新增空间

    2)、typedef这个结构体变量名为SLlinkList。如果你typedef这个结构体变量为SLinkList[LISTSIZE]要注意了,这样做有许多的缺点,会让你走许多的弯路。

      1.减少了灵活性,声明这个变量SLinkList L;这样就固定了100个空间的大小,你想申请200是不可能的;而typedef为SLinkList,声明这个变量时SLinkList L[345];这样是很灵活的。

      2.把访问结构体成员弄得很复杂,熟悉c就会知道指针需要用"->"访问、变量需要用"."访问,通过形参传地址修改必须要用*p。而c基础不过关的(比如说我)就会犯错误如结构体声明为typedef SLinkList[100]; SLinkList L; L[i]->data;这样访问,这是错误的访问方法,除了静态数组第一个也就是L[0]可以修改外,其他元素修改不了。正确的访问方式是先*L访问首地址,然后(*L+i)加上偏移量找到指定空间,这是一个指针,然后(*L+i)->data这才是正确的访问方式。

    分配地址空间:malloc分配或者变量自动分配

    1 SLinkList *L = (SLinkList *)malloc(sizeof(SLinkList) * LISTSIZE);
    2 或者
    3 SLinkList L[LISTSIZE];

    代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include "..custom.h"
      5 #include "..	est.c"
      6 
      7 /**
      8  * 静态链表,使用index的相对位置作为指针,方便在不设指针类型的程序中使用链表结构
      9  * 预先需要分配较大的数组空间
     10  * 说白了就是链表,只不过是片连续的地址空间
     11  */
     12 int LISTSIZE = 100;
     13 typedef int ElemType;
     14 typedef struct SLinkList {
     15   ElemType data;
     16   int cur;
     17 } SLinkList;
     18 
     19 /**
     20  * 初始化
     21  */
     22 void initSLinkList(SLinkList *L) {
     23   // L[0]->data保存未分配数组的长度,不包括第一个和最后一个
     24   for (int i = 0; i < LISTSIZE - 1; i++) {
     25     L[i].cur = i + 1;
     26   }
     27   L[0].data = LISTSIZE - 2;
     28   // L[LISTSIZE].cur分配了的结点的首地址,L[LISTSIZE].data保存分配了的长度
     29   L[LISTSIZE - 1].cur = 0;
     30   L[LISTSIZE - 1].data = 0;
     31 }
     32 
     33 /**
     34  * 遍历L
     35  */
     36 void traverseSLinkList(SLinkList *L) {
     37   if (L[LISTSIZE - 1].data == 0) return;
     38   int i = L[LISTSIZE - 1].cur;
     39   while (i != 0) {
     40     printf("%d	", L[i].data);
     41     i = L[i].cur;  // 类似于p=p->next
     42   }
     43   printf("
    ");
     44 }
     45 
     46 /**
     47  * 在第i个位置插入e
     48  */
     49 int listInsert(SLinkList *L, int i, ElemType e) {
     50   if (L[0].data == 0) {
     51     // L[0].data==0表明未分配的空间已经用完,重新分配一个空间
     52     printf("空间不足");
     53     return 0;
     54   }
     55   if (i > L[LISTSIZE - 1].data + 1) {
     56     printf("位置i不合法");
     57     return 0;
     58   }
     59   // 在未分配空间的L拿出一个空间来, 就拿第一个
     60   int index = L[0].cur;
     61   L[0].cur = L[index].cur;
     62 
     63   L[index].data = e;  // 为这个空间赋值
     64 
     65   // 找已分配链表的第i个位置
     66   int k = LISTSIZE - 1;
     67   for (int j = 0; j < i; j++) {
     68     k = L[k].cur;
     69   }
     70   L[index].cur = L[k].cur;  // 连接
     71   L[k].cur = index;
     72 
     73   L[0].data--;             // 用掉一个结点
     74   L[LISTSIZE - 1].data++;  // 增加一个分配了的结点
     75   return 1;
     76 }
     77 
     78 /**
     79  * 删除一个元素
     80  */
     81 int listDelete(SLinkList *L, int i, ElemType *e) {
     82   if (L[LISTSIZE - 1].data == 0) return 0;
     83   // 找到第i个位置
     84   int k = LISTSIZE - 1;
     85   for (int j = 0; j < i; j++) {
     86     k = L[k].cur;
     87   }
     88   int index = L[k].cur;
     89   L[k].cur = L[index].cur;
     90 
     91   *e = L[index].data;  // 赋值
     92 
     93   // 加入空闲的链表
     94   L[index].cur = L[0].cur;
     95   L[0].cur = index;
     96 
     97   L[0].data++;             // 增加一个未分配结点
     98   L[LISTSIZE - 1].data--;  // 减少一个分配了的结点
     99   return 1;
    100 }
    101 
    102 /**
    103  * 测试
    104  */
    105 void createList(SLinkList *L) {
    106   initSLinkList(L);
    107   for (int i = 0; i < 10; i++) {
    108     listInsert(L, i, i * 111);
    109   }
    110 }
    111 int main() {
    112   SLinkList *L = (SLinkList *)malloc(sizeof(SLinkList) * LISTSIZE);
    113   createList(L);
    114   traverseSLinkList(L);
    115   printf("空间总长度%d
    ", LISTSIZE);
    116   printf("已用空间长度%d
    ", L[LISTSIZE - 1].data);
    117   printf("未用空间长度%d
    ", L[0].data);
    118   ElemType e;
    119   listDelete(L, 2, &e);
    120   printf("e:%d
    ", e);
    121   listInsert(L, 1, 5);
    122   traverseSLinkList(L);
    123   printf("空间总长度%d
    ", LISTSIZE);
    124   printf("已用空间长度%d
    ", L[LISTSIZE - 1].data);
    125   printf("未用空间长度%d
    ", L[0].data);
    126   return 0;
    127 }

    总结:

    其它的就难得写了,静态数组思想大概就是这样。"严版"数据结构书上这一节写得云里雾里的,不仔细看和操练不容易搞出来。

    注意声明结构体数组不同,引用结构体成员的方式也不同;

    在懂得算法思想的基础上改进、创新代码。

  • 相关阅读:
    JS 实现鼠标移入移出透明度动画变化效果
    Undefined和null的本质区别
    网格布局知识点总结
    用CSS3搭建立方体
    缩放实例
    浮动与细线边框制作广告商标
    用伪元素制作列表菜单
    元素的分类与转换
    网易云导航栏
    CSS中内边距和宽度内减
  • 原文地址:https://www.cnblogs.com/xfk1999/p/12193594.html
Copyright © 2011-2022 走看看