游标实现链表及二叉树和BST树

代码地址:https://github.com/tofar/data-structure/tree/master/code/cursor

1. 链表的游标实现

诸如BASIC和FORTRAN等许多语言都不支持指针。如果需要链表而又不能使用指针,这时我们可以使用游标(cursor)实现法来实现链表。

在链表的实现中有两个重要的特点:

  1. 数据存储在一组结构体中。每一个结构体包含有数据以及指向下一个结构体的指针。
  2. 一个新的结构体可以通过调用malloc而从系统全局内存(global memory)得到,并可以通过free而被释放。

游标法必须能够模仿实现这两条特性:

满足条件1的逻辑方法是要有一个全局的结构体数组(模拟系统全局内存)。对于数组中的任何单元,其数组下标可以用来代表一个地址。

typedef int PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

struct Node {
    ElementType Element;
    Position Next;
};
struct Node cursor_space[ SPACE_SIZE ];

作为备用单链表,用来malloc或free游标可用空间,该表用0作为表头。刚开始时,freelist就是整个结构体数组。0指向的为空余空间的下标,若0指向0则表示没有空余空间。

需要理解的是:所有的链表,包括备用表和已用表,全部都在我们定义的全局结构体数组中,只是它们的表头不同,从不同的表头出发形成了不同的单链表。

假设我们定义了一个大小为11的游标空间,其初始化状态如下:

Slot Element Next
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 0

注:对于Next, 0的值等价于NULL指针。

上面的状态用链表形式表示为:cursor_space[0]—>cursor_space[1]—>cursor_space[2]—>cursor_space[3]—>cursor_space[4]—>cursor_space[5]—>cursor_space[6]—>cursor_space[7]—>cursor_space[8]—>cursor_space[9]—>cursor_space[10]—>NULL.

为执行malloc功能,将(在表头后面的)第一个元素从freelist中删除。为了执行free功能,我们将该单元放在freelist的前端。

malloc和free的游标实现如下:

/*cursor_alloc*/
Position cursor_alloc( void )
{
    Position p;
    p = cursor_space[0].Next;
    cursor_space[0].Next = cursor_space[p].Next;
    return p;  // 返回开辟空间,0永远指向空余空间
}
/*cursor_free*/
void cursor_free( Position p )
{
    cursor_space[p].Next = cursor_space[0].Next;
    cursor_space[0].Next = p;
}

为加深理解,请参考如下实例:

Slot Element Next
0 - 6
1 b 9
2 f 0
3 header 7
4 - 0
5 header 10
6 - 4
7 c 8
8 d 2
9 e 0
10 a 1

如果单链表L的值是5,M的值是3,我们又规定了freelist表头为0,因此,从上表中我们可以得到三个链表:

freelist:cursor_space[0]—>cursor_space[6]—>cursor_space[4]—>NULL

L:header—>a—>b—>e—>NULL

M:header—>c—>d—>f—>NULL

freelist是分配L、M链表后还剩余的可分配空间。

游标实现

/* return ture if L is empty */
int isempty(list L)
{
    return cursor_space[L].next = 0;
}
/* return true if P is the last position in list L */

int islast(position p, list L)
{
    return cursor_space[P].next == 0;
}
/* return position of X in L; 0 if not found */
/* uses a header node */

position find(element_type X, list L)
{
    position p;
    
    p = cursor_space[L].next;
    while(p && cursor_space[p].element != X)
        p = cursor_space[p].next;
    
    return p;
}
/* delete first occurence of X from a list */
/* assume use of a header node */

void delete(element_type X, list L)
{
    position p, tmpcell;
    
    p = find_previous(X, L);
    
    if(!islast(p, L))
    {
        tmpcell = cursor_space[p].next;
        cursor_space[p].next = cursor_space[tmpcell].next;
        cursor_free(tmpcell);
    }
}
/* insert (after legal position P) */

void insert(element_type X, list L, position P)
{
    position tmpcell;
    
    tmpcell = cursor_alloc();
    if(tmpcell == 0)
        fatal_error("out of sapce!!!");

    cursor_space[tmpcell].element = X;
    cursor_space[tmpcell].next = cursor_space[P].next;
    cursor_space[P].next = tmpcell;
}

2. 二叉树

typedef struct tREE
{
  int data;
  int left;
  int right;
} TREE;

和链表实现类似,再定义一个全局数组 tr[ ] 即可。

3. BST树

BST:即二叉搜索树:

  1. 所有非叶子结点至多拥有两个儿子(Left和Right);

  2. 所有结点存储一个关键字;

  3. 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

    img

    二叉树定义:

    //define a tree using cursors
    typedef struct tREE
    {
      int data;
      int left;
      int right;
    } TREE;
    

    寻找最小节点:

    //找到最小的节点
    static int find_min (int root)
    {
      if (tr[root].left < 0)
        return (root);
    
      return (find_min (tr[root].left));
    }
    

    插入:

    //插入
    static int insert (int root, int i)
    {
      if (root < 0)
      {
        return (i);
      }
    
      if (tr[i].data < tr[root].data)
        tr[root].left =  insert (tr[root].left, i) ;
      else if (tr[i].data > tr[root].data)
        tr[root].right = insert (tr[root].right, i) ;
    
      return (root);
    }
    

    删除:

    //删除节点i
    static int delete (int root, int i)
    {
      int tmp;
    
      if (root < 0)
        return (-1);
    
      if (tr[i].data < tr[root].data)
        tr[root].left = delete (tr[root].left, i);
      else if (tr[i].data > tr[root].data)
        tr[root].right = delete (tr[root].right, i);
      else if (tr[root].left > 0 && tr[root].right > 0)
      {
        tmp = find_min (tr[root].right);
        tr[root].data = tr[tmp].data;
        tr[root].right = delete (tr[root].right, tmp);
      }
      else if (tr[root].left > 0)
        return (tr[root].left);
      else
        return (tr[root].right);
    
      return (root);
    }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容