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

       双向链表也叫双链表,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任何一个节点开始,都可以很方便的访问它的前驱结点和后继节点。别人常常来构造双向循环链表,今天我们特立独行一下,先来尝试构造不带头结点双向非循环链表。示例代码上传至  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,否则返回0
int 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域的存储地址,否则返回NULL
int *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,否则返回0
int 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;
}

















你可能感兴趣的:(算法设计,经典算法学习)