虽然我了解到big O的符号只是描述了算法的增长率,但我不确定在以下O(n)算法之间现实生活中的效率是否有差异。
要从列表的末尾打印链表中的节点的值k个位置。
给定一个节点:
/* Link list node */
struct node
{
int data;
struct node* next;
};
解决方案1 O(n)
该解决方案遍历列表两次,一次查找列表的长度,第二次获取到列表的末尾。
void printNthFromLast(struct node* head, int n)
{
int len = 0, i;
struct node *temp = head;
// 1) Count the number of nodes in Linked List
while (temp != NULL)
{
temp = temp->next;
len++;
}
// Check if value of n is not more than length of the linked list
if (len < n)
return;
temp = head;
// 2) Get the (n-len+1)th node from the begining
for (i = 1; i < len-n+1; i++)
{
temp = temp->next;
}
printf ("%d", temp->data);
return;
}
解决方案2 O(n)
此解决方案只会遍历列表一次。 ref_ptr指针引导,第二个指针(main_ptr)跟随其后面的k个位置。当ref_ptr到达列表的末尾时,main_ptr应该指向正确的节点(k列表的末尾)。
void printNthFromLast(struct node *head, int n)
{
struct node *main_ptr = head;
struct node *ref_ptr = head;
int count = 0;
if(head != NULL)
{
while( count < n )
{
if(ref_ptr == NULL)
{
return;
}
ref_ptr = ref_ptr->next;
count++;
}
while(ref_ptr != NULL)
{
main_ptr = main_ptr->next;
ref_ptr = ref_ptr->next;
}
}
}
问题是:即使两个解决方案都是O(n),同时留下大的O表示法,第二个解决方案比第一个更长的列表更有效,因为它只会遍历列表一次?
是。在发生相同工作的具体示例中,单个循环可能比循环一组数据两次更有效。但是,O(2n)〜O(n)的思想是2 ns对1 ns可能不重要。 Big O可以更好地展示一段代码如何扩展,例如如果你做出循环O(n ^ 2),则O(n)与O(2n)的差距远小于O(n)vs O(n ^ 2)。
如果您的链表包含数据的数据,那么可能值得减少到单循环迭代。在这种情况下,大O指标可能不足以描述您的最坏情况;您将更好地计时代码并考虑应用程序的需求。
另一个例子是嵌入式软件,其中1 ms与2 ms可能是500 Hz和1 kHz控制回路之间的差异。
获得的教训是它取决于应用程序。
翻译自:https://stackoverflow.com/questions/35213434/while-we-drop-the-constant-in-big-o-notation-does-it-matter-in-real-life-situat