链表的数组实现中,令链表和自由表变得紧凑《算法导论》10.3-5

Posted meixiaogua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表的数组实现中,令链表和自由表变得紧凑《算法导论》10.3-5相关的知识,希望对你有一定的参考价值。

  • 有一个双向链表L,存储于长度为m的数组。假设m个元素中有n个元素在链表L中,m-n个元素由自由表F管理。现在实现方法CompacifyList,它的功能是让链表L中元素紧凑地占据数组的前n个元素,自由表F占据数组的后m-n个元素。运行时间O(n),只使用固定的额外存储空间。
  • 这道题可以这样来思考,数组[0,n)区间是L的地盘,数组[n,m)区间是F的地盘,我们想要的结果是L和F双方的元素都乖乖地待在自己家的地盘上。可是现在偏偏有一些淘气的元素跑到了别人家的地界上,且有多少个L元素跑去了F家里,相应地,就有多少F元素跑到了L家里。我们要做的是同时从L和F链表头开始查找,每当找出一个待在F家的L元素和一个待在L家的F元素,就对换他们两个的位置,这样他俩就都回到了自己家中。
#include <cassert>
#include <iostream>
using namespace std;

struct Object
{
    int prev;
    int key;
    int next;
};
constexpr int SIZE = 10;
Object array[SIZE];
int listHead;
int freeHead;
int listSize;
void CompacifyList()
{
    assert(listSize > 0);
    int freePrev = -1;
    int freeCur = freeHead;
    int freeNext = array[freeCur].next;
    int listPrev = array[listHead].prev;
    int listCur = listHead;
    int listNext = array[listHead].next;
    bool bNeedSwap = false;
    while(true)
    {
        //find next element of list to swap
        bNeedSwap = false;
        while(!bNeedSwap)
        {
            if(listCur < listSize)
            {
                listPrev = listCur;
                listCur = listNext;
                if(listCur == -1)
                    break;
                else
                    listNext = array[listCur].next;
            }
            else
            {
                bNeedSwap = true;
            }
        }
        if(listCur == -1)
            break;
        //find next element of freelist to swap
        bNeedSwap = false;
        while(!bNeedSwap)
        {
            if(freeCur >= listSize)
            {
                freePrev = freeCur;
                freeCur = freeNext;
                if(freeCur == -1)
                    break;
                else
                    freeNext = array[freeCur].next;
            }
            else
            {
                bNeedSwap = true;
            }
        }
        //swap
        int tmp = freeCur;
        freeCur = listCur;
        listCur = tmp;
        array[listCur].key = array[freeCur].key;
        //insert new listCur between listPrev and listNext
        array[listCur].prev = listPrev;
        array[listCur].next = listNext;
        if(listPrev != -1)
            array[listPrev].next = listCur;
        else
            listHead = listCur;    //处理被交换元素是链表头的边界情况
        if(listNext != -1)
            array[listNext].prev = listCur;
        //insert new freeCur between freePrev and freeNext
        if(freePrev != -1)
            array[freePrev].next = freeCur;
        else
            freeHead = freeCur;
        array[freeCur].next = freeNext;
    }
}

void Test()
{
    //there are 5 objects in list, index = 2 8 6 3 9, key = 1 2 3 4 5
    listHead = 2;
    array[2] = {-1, 1, 8};
    array[8] = {2, 2, 6};
    array[6] = {8, 3, 3};
    array[3] = {6, 4, 9};
    array[9] = {3, 5, -1};
    listSize = 5;
    //there are 5 object in freelist, index = 1 4 5 0 7
    freeHead = 1;
    array[1].next = 4;
    array[4].next = 5;
    array[5].next = 0;
    array[0].next = 7;
    array[7].next = -1;
    CompacifyList();
    //L元素都排在数组下标0~4位置上
    cout << "list elements:" << endl;
    cout << "pos" << "	" << "key" << endl;
    int curPos = listHead;
    while(curPos != -1)
    {
        cout << curPos << "	" << array[curPos].key << endl;
        curPos  = array[curPos].next;
    }
    //F元素都排在数组下标5~9位置上
    cout << "freeList elements:" << endl;
    curPos = freeHead;
    while(curPos != -1)
    {
        cout << curPos << endl;
        curPos = array[curPos].next;
    }
}

//运行结果是
list elements:
pos key
2   1
1   2
4   3
3   4
0   5
freeList elements:
8
6
5
9
7

//写给自己,我第一次写这段代码时出现的错误:
1. 忘记交换freeCur和listCur的值
2.忘记处理边界情况freeHead和listHead

以上是关于链表的数组实现中,令链表和自由表变得紧凑《算法导论》10.3-5的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法之数组链表和哈希表的Java实现

动态链表和静态链表

顺序表和链表的基本操作,用C语言实现!

C中线性表和链表的区别

C中线性表和链表的区别

单向链表和双向链表的原理及其相关实现