单链表的实现(不带头节点)

来源:互联网 发布:英雄创造历史 知乎 编辑:程序博客网 时间:2024/04/30 03:36
//单链表的操作 (不带表头节点)#include <stdlib.h>#include <stdio.h>#include <string.h>#define MALLOC(p,s) \if( !( (p) = malloc(s) ) ) { \    fprintf(stderr,"Insufficient memory.\n"); \    exit(EXIT_FAILURE); \}typedef struct listNode *listPtr;struct listNode{    int data;    listPtr link;};/* 1.初始化线性表,即置单链表的表头指针为空 */void initList(listPtr *pNode){    *pNode = NULL;    printf("initList函数执行,初始化成功\n");}//创建两个节点链表, first 指向第一个节点,second指向第二个节点//返回变量first指向表头listPtr create(){ /*  create a linked list with two node */    listPtr first, second;    MALLOC(first, sizeof(*first) );    MALLOC(second, sizeof(*second) );    second->link = NULL;    second->data = 20;    first ->data = 10;    first->link = second;    return first;}listPtr getNode(int item){    listPtr newNode;    MALLOC(newNode, sizeof(*newNode));    memset(newNode, 0, sizeof(*newNode));    newNode->data = item;    newNode->link = NULL;    return newNode;}//计算单链表的长度int length( listPtr lead ){    int len = 0;    while( lead )    {        ++len;        lead = lead->link;    }    return len;}//链表的插入,要在链表中的任意位置x之后插入一个节点,节点的数据域是50//函数的参数有两个,first指向表头,如果first为空指针,则返回后它的值//变成指向数据域为50的指针,由于这个指针的内容可能改变,必须传这个指针的地址//形参声明为listPtr *first,第二个参量值x不会改变,因此不用传它的地址。函数调用//语句应为insert(&first, x),first是表头,x指向插入的位置void insert(listPtr *first, listPtr x ){ /* insert a new node with data = 50 into the chain first after node x */    listPtr tempNode;    MALLOC(tempNode, sizeof(*tempNode));    tempNode->data = 50;    if ( *first )    { // not NULL        tempNode->link = x->link;  //在x与其后继节点之间插入tempNode指向的节点        x->link = tempNode;    }    else    { // empty list        tempNode->link = NULL;        *first = tempNode;    }}//在链表的表头插入一个元素,若成功返回1,失败返回0;int insertFront(listPtr *front, int x ){    listPtr p;    MALLOC(p, sizeof(*p) );    memset(p, 0, sizeof(*p) );    p->data = x;    p->link = (*front);    *front = p;    printf("向表头插入元素 %d 成功\n", x);    return 1;}//单链表的正向排序//将item插入到一个从小到大排序的有序链表中void insertSort(listPtr *front, const int item ){    listPtr newNode;    newNode = getNode(item);    if( *front == NULL )    {// empty list        *front = newNode;    }    else if ( (*front)->data >= newNode->data )    { // 在第一个节点之前插入        newNode->link = *front;        *front = newNode;    }    else    {        listPtr curr = *front;        listPtr prev = NULL;        //找到需要插入的位置        while(newNode->data > curr->data && curr->link != NULL )        {            prev = curr;            curr = curr->link;        }        //如果是在中间位置,把newNode插入到prev和curr之间        if ( curr->data >= newNode->data )        {            newNode->link = curr;            prev->link = newNode;        }        else        { //位置在末尾,把newNode插入到curr之后            curr->link = newNode;        }    }}//将一个节点按节点中值的升序插入到一个链表中listPtr insertNode( listPtr front, listPtr node ){    listPtr prev = NULL;    listPtr curr = front;    while( curr != NULL && curr->data < node->data )    {        prev = curr;        curr = curr->link;    }    if ( curr == front )    {        node->link = front;        front = node;    }    else    {  //插入到 prev和curr之间        prev->link = node;        node->link = curr;    }    return front;}//将两个有序链表head1和head2合并成一个链表,依然有序,使用递归方法以及非递归方法//非递归合并listPtr mergeList( listPtr head1, listPtr head2 ){    //若果有一个是空表则返回另一个    if ( head1 == NULL )        return head2;    if ( head2 == NULL )        return head1;    // neither list is NULL,find the shorter one    listPtr head ;  //指向两个表中较长的那个表的表头    listPtr p;  //指向较短的那个表表头    listPtr nextP;  //指向p之后    if(length(head1) > length(head2))    {        head = head1;        p = head2;    }    else    {        head  = head2;        p = head1;    }    //将较短表中的元素逐个插入到较长的表中    while ( p != NULL )    {        nextP = p->link; //保存p的下一结点        head = insertNode(head, p);  //将p插入到目标链表中        p = nextP;  // p指向将要插入的下一个节点    }    return head;}//递归合并两个有序链表listPtr mergeRecursive(listPtr head1, listPtr head2 ){    listPtr head = NULL;    if ( head1 == NULL )        return head2;    if (head2 == NULL )        return head1;    if (head1->data < head2->data )    {        head = head1;        head->link = mergeRecursive( head1->link, head2 );    }    else    {        head = head2;        head->link = mergeRecursive( head1, head2->link );    }    return head;}//打印链表,最先打印first的数据域,然后first的值用它自己的link域值替换//这样访问链表的所有节点知道结束。void printList(listPtr first ){    printf("The list contains: ");    for( ; first; first = first->link )        printf("%4d", first->data );    printf("\n");}//将链表反向listPtr invert(listPtr lead ){ /* invert the list pointed to by lead */    listPtr trail, middle;    middle = NULL;    while ( lead )    {        trail = middle;        middle = lead;        lead = lead->link;        middle->link = trail;    }    return middle;}//把两个单向链表ptr1, ptr2连接起来,函数复杂度是O(prt1长度)//函数不申请新节点,连接就放在ptr1中listPtr concatenate( listPtr ptr1, listPtr ptr2 ){ /* produce a new list that pointed to by ptr1   * is changed permanently */    listPtr temp;    /* check for empty lists */    if ( !ptr1 ) return ptr2;    if ( !ptr2 ) return ptr1;    /* neither list is empty, find end of first list */    for ( temp = ptr1; temp->link; temp = temp->link );    /* link end of first to start of second */    temp->link = ptr2;    return ptr1;}//清空链表,当程序不再需要链表时,应当即使释放链表所占用的内存//通过重复删除表头节点直至链表为空(front = NULL)来清空一个链表void freeList(listPtr *front){    listPtr p;    //不能删除空链表的front节点    while( *front != NULL)    {        // p指向原来的front节点        p = *front;        //把front移到下一个节点        *front = (*front)->link;        free( p );    }    printf("已清空链表\n");}//在链表总查找具有特定值target的第一个节点,若查找成功返回指向该节点的指针,失败返回NULLlistPtr find( listPtr front, const int target ){    listPtr p = front;    while ( p != NULL && p->data != target )    {        p = p->link;    }    return p;}//删除链表中的节点,删除节点需要考虑节点所在的位置。 假设first指向表头,x指向待删除节点,//指向x的直接前驱节点。如果待删除节点是表头,因此必须改变first的值,如果不是表头节点只需要//将trail的链域改变,让它指向x所指向的节点即可void deleteNode(listPtr *first, listPtr x ){ /* delete x from the list, trail is the preceding node   * and *first is the front of the list   */   listPtr trail;  // 指向x的前驱节点   if ( x == (*first) )        trail = NULL;    else    { // x  is not the first, find the position of trail        for(trail = *first; trail->link != x; trail= trail->link);    }   if(trail != NULL)   { //trail is not NULL, means it is not the first        trail->link = x->link;   }   else   {        *first = (*first)->link;   }   free(x);}//判断一位链表是否有环, 有环返回1,无环返回0int hasLoop(listPtr front){    listPtr fast = front;    listPtr slow = front;    while(fast != NULL && fast->link != NULL)    {        slow = slow->link; // 1 step        fast = fast->link->link;  // 2 step        if( fast == slow)            return 1;    }    return 0;}//删除一个具有特定值的节点,如果链表中存在值target则删除找到的第一个匹配的节点//否则不改变链表。函数可能会改变头结点,所以要传递该指针的地址或引用void eraseValue(listPtr *front, const int target){    int found = 0;  //如果找到节点,将设置为1    listPtr curr;  //用于遍历链表    listPtr trail; // 跟在curr的后面    curr = *front;    trail = NULL;    //扫面链表直到找到目标节点或者到达链表尾    while ( curr != NULL && !found )    {        if( curr->data == target )        {  // have a match            //要删除的是不是表头节点            if(trail == NULL)            {                *front = (*front)->link;  // remove the first node            }            else            {                trail->link = curr->link;  // erase the intermediate node            }            free(curr);            found = 1;        }        else        {            trail = curr;            curr = curr->link;        }    }}int main(){    listPtr list1 = create();    insertFront(&list1,30);    insertFront(&list1, 40);    printList(list1);    listPtr list2 = create();    list2 = invert(list2);    printList(list2);    listPtr list3 = concatenate(list1, list2);    printList(list3);    listPtr p = find(list3, 10);    deleteNode(&list3, p);    printList(list3);    int size = length(list3);    printf("The size of list3 is: %d\n", size);    freeList(&list3);    listPtr head = getNode(3);    int i;    for (i = 10; i > 0; i--)        insertSort(&head, i);    printList(head);    insertNode(head,getNode(100));    printList(head);    listPtr k;    initList(&k);        for (i = 10; i > 0; i--)        k = insertNode(k, getNode(i+10));    printList(k);    listPtr j  = NULL;    for (i = 17; i < 25; i++)        j = insertNode(j, getNode(i));    printList(j);    //listPtr m = mergeList(j,k);    listPtr m = mergeRecursive(j, k);    printList(m);    return 0;}

0 0
原创粉丝点击