Общий размер связанного списка в C

хорошо... мое введение в структуры данных из CS настолько ржавое, что мне нужно спросить об этом здесь.

у меня есть связанный список, структура которого является:

struct Data_Struct {
    char *Name;
    char *Task;
    char *Pos;
    struct Data_Struct *Next;
};
typedef struct Data_Struct MyData;

теперь, в какой-то момент в моем приложении я заполнил список данными.

вопрос в том, как получить общий размер данных, хранящихся там? Сколько здесь символов? Что-то вроде

sizeof(MyData);

это вернет размер информации, хранящейся в списке.

код оцененный.

спасибо!

редактировать: К сожалению, это не домашнее задание. Я закончил школу более 20 лет назад, и, честно говоря, мне никогда не приходилось использовать связанные списки. Я просто не помню. Я делаю итерацию списка и получаю strlen () каждого элемента и сохраняю его на глобальном размере, но я хотел знать, есть ли лучший способ.

и нет, мне не нужен размер связан лайков (количество узлов), я просто хочу знайте, сколько символов хранится там.

спасибо

7 ответов


вы обычно проходите через список, пока не достигнете хвостового элемента, считая в то же время, код должен быть примерно таким:

int listLength(struct Data_Struct* item)
{
  struct Data_Struct* cur = item;
  int size = 0;

  while (cur != null)
  {
    ++size;
    cur = cur->Next;
  }

  return size;
}

имейте в виду, что сложность этой операции линейна с размером списка, поэтому это O (n) и это довольно неэффективно. Вы можете хранить размер где-то и обновлять со вставками и удалениями списка, чтобы избежать каких-либо накладных расходов и иметь возможность вычислять его в постоянное время O (1).

EDIT: Не заметил, что вы хотите размер всех данных, включенных в список. В вашем случае вы можете сохранить тот же подход, используемый для вычисления длины, но вместо этого добавить 1 для каждого элемента вы должны добавить общая длина строки:

size += strlen(Name)+strlen(Task)+strlen(Pos);

виду, что поскольку данные внутри элемента списка, если типа char* эффективная площадь Data_Struct это всего лишь 4 указателя, поэтому вам нужно использовать функция поддержки как strlen, иначе вы не можете сделать реальные размер строки.

в чем разница?

sizeof(Data_Struct) == 16

потому что Data_Struct type содержит 4 указателя, три для указателей на char и один для следующего элемента в списке

sizeof(Name) == sizeof(Task) == sizeof(Pos) == 4

потому что эти переменные имеют тип указатель на char, поэтому они являются указателем, без конкретного значения, и обычно это 4 байта (я предполагаю 32 бит архитектура)

strlen(Name) == length in chars of the string

потому что функция работает точно так же для вычисления длины строки.


Ну, вы можете пересечь список, чтобы вычислить количество довольно легко. Очевидно, что общая память будет равна количеству элементов, умноженному на размер каждого элемента (sizeof(Data_Struct)).

конечно, это будет размер самого связанного списка и не включает память, выделенную для строк. Указатель не имеет никакой информации о количестве выделенной памяти, на которую он ссылается, поэтому, строго говоря, вы не можете рассчитать общий объем выделенной памяти напрямую, просто глядя на связанный список, как это. Кроме того, в связанном списке могут быть дубликаты указателей, которые вам нужно будет отслеживать. Тем не менее, предполагая, что все указатели уникальны, вы можете вычислить количество символов в каждом элементе, суммируя возвращаемые значения strlen вызывает каждый указатель, когда вы пересекаете список (который должен быть довольно простым).


как только вы выделите память для узла (используя malloc), вы сможете сделать sizeof(yourDataType). Таким образом, чтобы получить общий размер связанного списка, вы пересекаете список и получаете количество узлов:

Total Size Of Linked List = SizeOf(One Node) * Count Of Nodes

например:

int getCountOfList()
{
 Node* temp = head; //assign a temp node to the head of the list
 int count=0;

 while(temp) {
  count++;
  temp = temp->next; //move to next node
 }
 return count;
}

затем вы берете этот счет и умножаете на размер:

size = getCountOfList * sizeof (mydatatype);

это даст вам размер фактического связанного списка, но becareful как узел связанного списка имеет элементы указателя, которые сами по себе могут выделять память. Это нужно будет учесть...

например, один из этих элементов char* в узле может malloc немного больше места и использовать некоторую память.

Если вам действительно нужен весь размер списка, включая выделенные элементы для всех других указателей char*, например, вы просто:

1) пересечь список и посмотреть в каждом узле

2)для каждого узла вы проверяете, указывают ли элементы каждого узла на любое другое распределение (для экземпляр char * data может выделять 50 символов для хранения). Если это не null, вы получаете длину строки + 1(для завершения char), и вы умножаете это на sizeof (char) (для этого примера)

3) Вы делаете это для каждого узла и сохраняете этот размер, а затем переходите к следующему узлу

4) вы берете сумму всех этих символов* (в данном случае) для каждого узла и накапливаете для всего список.

5) Как только у вас есть, просто добавьте эту сумму, которая даст вам размер всех узлов.

тогда общий размер будет:

SizeOfAllNode + (SizeOf(dataType) * CountOfNodes)

держите счетчик при добавлении или удалении узлов. Таким образом, вам не нужно ходить по списку, суммируя каждый узел каждый раз, когда вы хотите подсчитать. Просто ссылайтесь на свое актуальное значение.


чтобы вычислить размер самого списка, просто возьмите sizeof(MyData) и умножить на количество узлов.

Если вы хотите включить размер строковых данных в список, вы можете вычислить память, используемую строкой как (strlen(str) + 1) * sizeof(char) - это предполагает, конечно, что строка была выделена точно в правильном размере.


Если вам нужно получить размер данных более одного раза, тогда было бы разумнее отслеживать его, когда вы добавили элементы в список, но код, чтобы понять это, довольно прост.

 size_t cb = 0;
 int    cItems = 0;
 struct Data_Struct * pnext = &MyData;
 while (pnext)
    {
    if (pnext->Name)
       cb += (strlen(pnext->Name)+1) * sizeof(char);
    if (pnext->Task)
       cb += (strlen(pnext->Task)+1) * sizeof(char);
    if (pnext->Pos)
       cb += (strlen(pnext->Pos)+1) * sizeof(char);
    ++cItems;
    pnext = pnext->Next;
    }

 // cb has the total size of the strings, now add the size of the data structs
 cb += sizeof(struct Data_Struct) * cItems;

вы можете перебирать все члены списка и накапливать количество символов в имени, задаче и Pos.

однако, если вы собираетесь сделать это несколько раз, я бы сохранил количество символов каждого поля при заполнении узла вместо того, чтобы считать их один раз и еще раз.

Итак, ваша структура будет определена следующим образом:

struct Data_Struct {
    char *Name;
    int   NameCount;

    char *Task;
    int   TaskCount;

    char *Pos;
    int   PosCount;
    struct Data_Struct *Next;
};
typedef struct Data_Struct MyData;

и итерация по списку может быть чем-то вроде:

void getCharacterCount(struct Data_Struct* data, int* nameCount, int* taskCount, int* posCount)
{
  struct Data_Struct* auxData = data;
  int nc = tc = pc = 0;

  for (; auxData; auxData = auxData->Next())
  {
    nc += auxData->NameCount; 
    tc += auxData->TaskCount;
    pc += auxData->PosCount;
  }

  *nameCount = nc;
  *taskCount = tc;
  *posCount  = pc;
}