1. 程式人生 > >鏈表的數組實現中,令鏈表和自由表變得緊湊《算法導論》10.3-5

鏈表的數組實現中,令鏈表和自由表變得緊湊《算法導論》10.3-5

bject and elements 多少 lse tex com spa 使用

  • 有一個雙向鏈表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" << "\t" << "key" << endl;
    int curPos = listHead;
    while(curPos != -1)
    {
        cout << curPos << "\t" << 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