C语言实现双向非循环链表(不带头结点)的基本操作

来源:互联网 发布:荷芳抢票软件 编辑:程序博客网 时间:2024/04/30 05:45

       双向链表也叫双链表,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任何一个节点开始,都可以很方便的访问它的前驱结点和后继节点。别人常常来构造双向循环链表,今天我们特立独行一下,先来尝试构造不带头结点双向非循环链表。示例代码上传至  https://github.com/chenyufeng1991/DoubleLinkedList 。

(1)定义不带头结点的双向非循环链表的节点类型

typedef struct NodeList{    int element;    struct NodeList *prior;    struct NodeList *next;}Node;


(2)初始化双链表

//1.初始化不带头结点的非循环双向链表void initList(Node *pNode){    pNode = NULL;    printf("%s函数执行,链表初始化完成\n",__FUNCTION__);}


(3)尾插法构造双向非循环链表:

//创建非循环双向链表Node *createList(Node *pNode){    Node *pInsert;    Node *pMove;    pInsert = (Node*)malloc(sizeof(Node));    memset(pInsert, 0, sizeof(Node));    pInsert->next = NULL;    pInsert->prior = NULL;    scanf("%d",&(pInsert->element));    pMove = pNode;    if (pInsert->element <= 0) {        printf("%s函数执行,输入数据非法,建立链表停止\n",__FUNCTION__);        return NULL;    }    while (pInsert->element > 0) {        if (pNode == NULL) {            pNode = pInsert;            pMove = pNode;        }else{            pMove->next = pInsert;            pInsert->prior = pMove;            pMove = pMove->next;        }        pInsert = (Node *)malloc(sizeof(Node));        memset(pInsert, 0, sizeof(Node));        pInsert->next = NULL;        pInsert->prior = NULL;        scanf("%d",&(pInsert->element));    }    printf("%s函数执行,建立链表成功\n",__FUNCTION__);    return pNode;}


(4)打印非循环双向链表

//3.打印非循环双向链表void printList(Node *pNode){    if (pNode == NULL) {        printf("%s函数执行,链表为空,打印失败\n",__FUNCTION__);    }else{        while (pNode != NULL) {            printf("%d ",pNode->element);            pNode = pNode->next;        }        printf("\n");    }}

(5)清空链表

//4.清除线性表L中的所有元素,使之成为一个空表Node *clearList(Node *pNode){    if (pNode == NULL) {        printf("%s函数执行,原链表就是空链表,无须执行该方法\n",__FUNCTION__);        return  NULL;    }else{        while (pNode->next != NULL) {            //一次删除每一个节点            pNode = pNode->next;            free(pNode->prior);            pNode->prior = NULL;        }        //清除最后一个节点        free(pNode);        pNode = NULL;        printf("%s函数执行,双向非循环链表清空成功\n",__FUNCTION__);        return pNode;    }}

(6)计算链表长度

//5.返回不带头节点的双向链表的长度int sizeList(Node *pNode){    int i = 0;    if (pNode == NULL) {        printf("%s函数执行,链表为空,长度为0\n",__FUNCTION__);        return 0;    }else{        while (pNode != NULL) {            i++;            pNode = pNode->next;        }        printf("%s函数执行,链表长度为%d\n",__FUNCTION__,i);        return i;    }}


(7)判断链表是否为空

//6.检查双链表链表是否为空,若为空则返回1,否则返回0int isEmptyList(Node *pNode){    if (pNode == NULL) {        printf("%s函数执行,当前链表为空\n",__FUNCTION__);        return 1;    }    printf("%s函数执行,当前链表非空\n",__FUNCTION__);    return 0;}

(8)查找双链表某个位置的元素

//7.返回不带头节点的双向非循环链表中第pos位置的元素int getElement(Node *pNode,int pos){    int i = 1;    Node *pMove;    pMove = pNode;    while (pMove != NULL) {        if (i == pos) {            printf("%s函数执行,第pos=%d位置的元素是%d\n",__FUNCTION__,pos,pMove->element);            return pMove->element;        }        i++;        pMove = pMove->next;    }    printf("%s函数执行,获取pos位置的元素失败\n",__FUNCTION__);    return -1;}


(9)返回某元素在链表中的内存地址

//8.从不带头结点的双链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULLint *getElemAddr(Node *pNode,int x){    Node *pMove;    pMove = pNode;    while (pMove != NULL) {        if (pMove->element == x) {            printf("%s函数执行,x=%d元素的内存地址为:0x%x\n",__FUNCTION__,x,&(pMove->element));            return &(pMove->element);        }        pMove = pMove->next;    }    printf("%s函数执行,获取x=%d内存地址失败\n",__FUNCTION__,x);    return &(pMove->element);}

(10)修改某个节点的值

//9.把双链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0int modifyElem(Node *pNode,int pos,int x){    int i = 1;    Node *pMove;    pMove = pNode;    while (pMove != NULL) {        if (i == pos) {            pMove->element = x;            printf("%s函数执行,修改pos=%d位置的元素成功\n",__FUNCTION__,pos);            return 1;        }        i++;        pMove = pMove->next;    }    printf("%s函数执行,修改pos=%d位置的元素失败\n",__FUNCTION__,pos);    return 1;}

(11)表头插入一个节点

//10.向不带头结点的非循环双向链表头部插入一个节点Node *insertHeadList(Node *pNode,int x){    Node *pInsert;    pInsert = (Node*)malloc(sizeof(Node));    memset(pInsert, 0, sizeof(Node));    pInsert->next = NULL;    pInsert->prior = NULL;    pInsert->element = x;    //这里要考虑原链表为空的情况    if (pNode == NULL) {        pNode = pInsert;        printf("%s函数执行,在头部插入节点成功\n",__FUNCTION__);        return pNode;    }    pInsert->next = pNode;    pNode->prior = pInsert;    pNode = pInsert;    printf("%s函数执行,在头部插入节点成功\n",__FUNCTION__);    return pNode;}


(12)表尾插入一个节点

//11.向不带头结点的非循环双向链表尾部插入一个节点Node *insertTailList(Node *pNode,int x){    Node *pMove;    Node *pInsert;    pInsert = (Node*)malloc(sizeof(Node));    memset(pInsert, 0, sizeof(Node));    pInsert->next = NULL;    pInsert->prior = NULL;    pInsert->element = x;    pMove = pNode;    //这里要考虑原链表为空的情况    if (pNode == NULL) {        pNode = pInsert;        printf("%s函数执行,在尾部插入节点成功\n",__FUNCTION__);        return pNode;    }    while (pMove->next != NULL) {        pMove = pMove->next;    }    pMove->next = pInsert;    pInsert->prior = pMove;    printf("%s函数执行,在尾部插入节点成功\n",__FUNCTION__);    return pNode;}


(13)测试函数

int main(int argc, const char * argv[]) {    Node *pList;    initList(pList);    printList(pList);    sizeList(pList);    pList = createList(pList);    printList(pList);    sizeList(pList);    isEmptyList(pList);    getElement(pList, 4);    getElemAddr(pList, 5);    modifyElem(pList, 4, 1111);    printList(pList);    pList = insertHeadList(pList, 8888);    printList(pList);    pList = insertTailList(pList,9999);    printList(pList);    pList = clearList(pList);    printList(pList);        return 0;}

















2 0