链表

优点:插入删除比顺序表快
缺点:不能随机访问

结构

typdef struct listNode_{
	DataType data;    //数据域
	listNode *next;    //指针域
}listNode,*linkedList;    //linkedList用于声明头指针
  • 首元节点:第一个存数据的节点
  • 头指针:指向链表第一个节点的指针
  • 为了使首元节点和其他节点的删除插入操作一致,在表头添加头节点,头节点的next指向首元节点,head指针指向头节点

初始化

申请一块头节点,头节点的指针域指向空,返回头节点地址

linkedList initialLinkedList(){
	listNode *head = new listNode;  
	if (!head) {  
	    cout << "申请失败" << endl;  
	    return nullptr;  
	}
	head->next = nullptr;  
	return head;
}

插入

头插法

插入节点newNode,更新newNode的指针域,再更新头节点head的指针域

linkedList head_insert(linkedList head, int key) {  
    listNode *newNode = new listNode;  
    newNode->data = key;  
    newNode->next = head->next;  
    head->next = newNode;  
    return head;  
}

尾插法

先通过遍历找到尾节点,再更新原尾节点的指针域

linkedList rear_insert(linkedList head, int key) {  
    listNode *newNode = new listNode;  
    newNode->data = key;  
    listNode *p = head;  
    while (p->next) {  
       p = p->next;  
    }  
    newNode->next = p->next;  
    p->next = newNode;  
    return head;  
}
  • 优化:用指针rear记录尾节点,每次尾插之后更新rear指针

查找

通过遍历查找

listNode *find(linkedList head, int key) {  
    listNode *p = head->next;  
    if (!p) {  
       cout << "链表为空" << endl;  
       return p;  
    }  
    while (p && p->data != key) {  //先判空再比较,反过来会非法访问
       p = p->next;  
    }  
    if (!p)cout << "没找到" << endl;  
    return p;  
}

删除

  • 将要删除的节点的前驱的指针域指向要删除节点的后继
  • 回收要删除的节点
linkedList Delete(linkedList head, int key) {  
    listNode *p = head->next;  
    while (p->next && p->next->data != key) {  
       p = p->next;  
    }  
    if (p->next == nullptr) {  
       cout << "未找到" << endl;  
       return head;  
    }  
    
    listNode *temp = p->next;  
    p->next = p->next->next;  
    delete temp;  
    temp=nullptr;    //防止temp成为野指针
    return head;  
}

双向链表与循环链表与单链表类似

双向链表

结构

struct listNode {  
    int data;  
    listNode *pre, *next;  
};

初始化

LinkedList initial() {  
    LinkedList head = new listNode;  
    head->next = head->pre = nullptr;  
    return head;  
}

插入

头插法

LinkedList head_insert(LinkedList head, int key) {  
    listNode *newNode = new listNode;  
    newNode->data = key;  
    newNode->next = head->next;  
    head->next = newNode;  
    newNode->pre = head;  
    if (newNode->next)  
       newNode->next->pre = newNode;  
    return head;  
}

尾插法

LinkedList rear_insert(LinkedList head, int key) {  
    listNode *newNode = new listNode;  
    newNode->data = key;  
    listNode *p = head;  
    while (p->next) {  
       p = p->next;  
    }  
    newNode->next = nullptr;  
    newNode->pre = p;  
    p->next = newNode;  
    return head;  
}

删除

LinkedList Delete(LinkedList head, int key) {  
    listNode *p = head->next;  
    while (p && p->data != key) {  
       p = p->next;  
    }  
    if (!p) {  
       cout << "未找到" << endl;  
       return head;  
    }  
    p->pre->next = p->next;  
    if (p->next)p->next->pre = p->pre;  
    delete p;  
    p = nullptr;  
    return head;  
}

循环链表

循环链表默认有头节点,循环链表的尾节点的next指针域指向头节点

  • 初始化循环链表时,头节点的指针域指向自己
posted @ 2026-04-18 16:40  mofei1116  阅读(10)  评论(0)    收藏  举报