C++中双向链表头插需判空,单向链表为何无需?
为什么C++中双向链表的头插方法与单向链表不同?
先看两段分别实现单向链表和双向链表头插功能的C++代码,核心疑问是:单向链表的头插函数不需要处理head为NULL的特殊情况,但双向链表如果不做判空处理就无法正常运行,这是为什么?
单向链表实现代码
#include <iostream> using namespace std ; // starting with linked list class node { public : int data ; node * next ; // constructor node ( int value){ data = value ; next = NULL ; } }; int insertathead( node *&head , int data ){ node*newhead ; newhead = new node(data) ; newhead -> next = head ; head = newhead ; } void print(node*& head) { node* temp = head; while (temp != NULL) { cout << temp->data << " -> "; temp = temp->next; } cout << "NULL" << endl; } int main () { node* node1 = NULL ; insertathead(node1, 5 ) ; insertathead( node1 , 10) ; insertathead(node1 , 15 ) ; insertathead( node1 , 20 ) ; insertathead( node1 , 30 ) ; print ( node1 ) ; return 0 ; }
双向链表实现代码
#include <iostream> using namespace std ; class node { public : int data; node*next ; node* prev ; // constructor node( int data ) { this -> data = data ; next = NULL ; prev = NULL ; } } ; void insertathead ( node*&head , int d ) { if ( head == NULL ) { node*temp = new node(d) ; head = temp ; } else {node*temp = new node(d) ; temp -> next = head ; head -> prev = temp ; head = temp ;} } void print ( node**head ){ node*temp = *head ; while ( temp != NULL ) { cout << temp -> data << " -> " ; temp = temp -> next ; } cout << "NULL " ; } int main () { node* head = NULL ; insertathead( head , 5 ) ; insertathead( head , 10) ; insertathead( head , 15 ) ; insertathead(head , 20 ) ; insertathead(head , 30 ) ; print ( &head ) ; return 0 ; }
核心疑问
在单向链表的insertathead函数中无需处理head为NULL的特殊情况,但双向链表若不加入该判空逻辑则无法正常打印链表,请问这是为什么?
原因解析
直接拆解两种链表头插的操作差异:
单向链表的头插逻辑
当head为NULL时,执行newhead->next = head只是把新节点的next设为NULL,之后把head指向新节点。整个过程没有对head指向的内存进行读写——毕竟此时head是空指针,我们只操作新节点的成员,不会触发空指针访问错误,所以不需要判空。双向链表的头插逻辑(无判空时的问题)
如果去掉双向链表insertathead里的if(head==NULL)判断,第一次插入节点(head为NULL)时,代码会执行:
temp -> next = head; // 这步没问题,temp->next被设为NULL head -> prev = temp; // 这里直接报错!head是NULL,访问head->prev属于空指针解引用,会触发程序崩溃、打印乱码等未定义行为
双向链表需要维护prev指针,头插时需要修改原head的prev指向新节点。但当原head是NULL时,根本没有可访问的内存空间去赋值,这就导致了错误。而单向链表没有这一步修改原头节点成员的操作,所以不需要判空。
简单总结:单向链表头插只操作新节点的next,不碰原head的成员;双向链表头插需要修改原head的prev,当原head为空时这步操作会引发空指针错误,因此必须先判空处理第一个节点的情况。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

