双链表的基本操作

来源:互联网 发布:软件企业人才需求 编辑:程序博客网 时间:2024/05/22 10:40

   在单链表的基本操作中简单说明了单链表相关的问题,双链表与单链表极为相似,所不同的是,双链表的每个结点除了包含数据域data,指向后继结点的指针域next外,多了一个指向前一结点的指针域pre。这样一来,从某一个结点开始,不仅可以向后遍历链表,还可以向前遍历链表。

   对应单链表的基本操作来看,双链表的基本操作同样包括创建链表、插入结点、删除结点、获取链表长度、逆置链表、链表排序、清空链表、销毁链表。对应操作的方式也基本相似,但是还是有些需要特别注意的地方。

   双链表中每个结点都多了一个指针,对于某些操作来说,更加方便了,比如删除结点时,只需要一个临时指针即可。但是,因为要操作更多的指针,为了防止误操作,就要考虑更多的边界条件了。

  • 插入结点时,基本的操作过程是,根据给定的数据创建一个新结点newNode,然后将newNode插入到head和首结点之间,在此过程中需要对首结点的指针域赋值,但是,如果链表本身就是一个空链表,那么首结点是不存在,此时任何通过首结点指针操作数据的行为都将导致运行时错误。所以,插入第一个结点的时候,要特殊处理。

  • 删除结点时,基本的操作过程是,定位好待删除结点temp后,将temp结点从链表中抽走,只要让temp结点的前序结点next指针指向temp结点的后续结点,同时让temp结点的后续结点的pre指针指向temp结点的前序结点即可。因为定义了头结点,所以无论待删除的结点位于链表中何处,其前序结点都是存在的,但是,如果待删除的结点时链表中的最后一个结点,那么其后续结点也是不存在的,此时只需要将其前序结点的next指针置空即可。所以,删除最后一个结点时,要特殊处理。

  • 清空链表的本质就是逐个删除结点,因此,也涉及到删除最后一个结点,需要特殊处理。

  • 相比于单链表的逆置,双链表的逆置要直观一点,只需借助两个指针变量ptemp(因为可以通过pre指针访问前序结点)。

  • 双链表的排序仍然采用冒泡排序,主要目的还是尽量避免指针的操作,减小出错的可能性。对于冒泡排序,要注意每次循环比较的次数。


代码实现

DoubleLinkedList.h

#ifndef _DOUBLE_LIST_H_#define _DOUBLE_LIST_H_#include <stdio.h>#include <stdlib.h>#include <iostream>#include <iomanip>using namespace std;typedef struct node {    int data;    struct node * pre;    struct node * next;}dNode;dNode * createDList();int getLength(dNode * head);void printDList(dNode * head);bool insertNode(dNode * head, int e);bool deleteNode(dNode * head, int idx);void reverseDList(dNode * head);void sortDList(dNode * head);void emptyDList(dNode * head);void destroyDList(dNode * head);#endif

DoubleLinkedList.cpp

#include "DoubleLinkedList.h"dNode * createDList(){    dNode * head;    head = (dNode *)malloc(sizeof(dNode));    if(!head){        return NULL;    }    head->data = 0;    head->pre = NULL;    head->next = NULL;    return head;}int getLength(dNode * head){    if(!head){        return -1;    }    return head->data;}void printDList(dNode * head){    dNode * temp;    if(!head){        return;    }    temp = head->next;    while(temp){        cout << left << setw(5) << temp->data;        temp = temp->next;    }    cout << endl;}bool insertNode(dNode *head, int e){    dNode * newNode;    if(head == NULL){        return false;    }    newNode = (dNode *)malloc(sizeof(dNode));    if(!newNode){        return false;    }    newNode->data = e;    newNode->next = head->next;    newNode->pre = head;    if(head->next){        head->next->pre = newNode;    }    head->next = newNode;    head->data ++;    return true;}bool deleteNode(dNode * head, int idx){    dNode * temp;    int length,i;    if(!head){        return false;    }    length = getLength(head);    if(idx>=length){        return false;    }    temp = head->next;    for(i=0;i<length;i++){        if(i == idx){            temp->pre->next = temp->next;            if(temp->next){                temp->next->pre = temp->pre;            }            temp->next = NULL;            temp->pre = NULL;            free(temp);            head->data --;            break;        } else {            temp = temp->next;        }    }    return true;}void reverseDList(dNode * head){    dNode * p, * temp;    if(!head){        return;    }    if(getLength(head) <= 1){        return ;    }    p = head->next;    temp = p->next;    p->pre = NULL;    while(temp){        p->next = p->pre;        p->pre = temp;        p = temp;        temp = p->next;    }    p->next = p->pre;    p->pre = head;    head->next = p;}void sortDList(dNode * head){    int e;    int length;    int i,j;    dNode * p, * q;    if(!head){        return ;    }    length = getLength(head);    if(length <= 1){        return;    }    for(i=1;i<length;i++){        p = head->next;        q = p->next;        for(j=length-i;j>=1;j--){            if(p->data > q->data){                e = p->data;                p->data = q->data;                q->data = e;            }            p = q;            q = p->next;        }    }}void emptyDList(dNode *head){    dNode * temp;    if(!head){        return;    }    if(getLength(head) == 0){        return;    }    temp = head->next;    while(temp){        temp->pre->next = temp->next;        if(temp->next){            temp->next->pre = temp->pre;        }        temp->next = NULL;        temp->pre = NULL;        free(temp);        temp = head->next;    }    head->data = 0;}void destroyDList(dNode * head){    if(!head){        return;    }    emptyDList(head);    free(head);}

test.cpp

#include "DoubleLinkedList.h"int main(){    int i;    dNode * head;    int rawData[] = {1,3, 2, 5, 7, 9, 6, 0};    head = createDList();    if(!head){        cout << "can't create double linked list!" << endl;    }    for(i=0;i<sizeof(rawData)/sizeof(int);i++){        insertNode(head,rawData[i]);    }    printDList(head);    insertNode(head,10);    cout << "current list length : " << getLength(head) << endl;    printDList(head);    deleteNode(head,8);    printDList(head);    reverseDList(head);    printDList(head);    sortDList(head);    printDList(head);    emptyDList(head);    cout << "current list length : " << head->data << endl;    destroyDList(head);    return 0;}

运行结果
运行结果

   指针真的是一把双刃剑,用得好,它能帮你轻而易举地完成自己想做的事,否则的话,一旦错误出现,你可能得绞尽脑汁才能发现问题所在。根据经验判断,一旦程序编译通过,运行着运行着就意外终止了,极有可能就是哪一处指针的操作出了问题。所以,当你看到一个指针的时候,一定要注意提醒自己,这是一个指针

0 0
原创粉丝点击