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

//单链表的操作 (不带表头节点)
#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的第一个节点,若查找成功返回指向该节点的指针,失败返回NULL
listPtr 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,无环返回0
int 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值