单链表实现

LinkList.h

#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0

typedef int ElemType;//假定线性表的元素类型为整型


//定义单链表的节点
typedef struct node 
{
    int data;
    struct node *pNext;
}LinkListNode;


///创建带有头节点的链表Init
///函数的返回值是头节点,没有参数
LinkListNode* InitLinkList(void);


///求长度:求顺序表中的元素的个数
///函数的返回值是顺序表的长度,参数pHead:是单链表的头节点
int GetSizeLinkList(LinkListNode* pHead);


///取元素:取给定位置的元素值
///返回值:第i个元素的地址,pHead:头指针,i 待查节点的序号
LinkListNode* GetLinkListNode(LinkListNode* pHead, int pos);


///查元素:查找给定元素值的位置
///返回值:节点的地址,找不到就返回NULL
///pHead:单链表的头指针,objData:是需要匹配的元素值
LinkListNode* LocateLinkList(LinkListNode* pHead, int objData);


///插入元素:在指定的位置插入给定的值
///尾插法建立单链表(将逻辑上的顺序表放入单链表的物理结构当中)
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Rear_LkList(ElemType arr[], int length);


///头插法建立单链表
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front1_LkList(ElemType arr[], int length);


///头插法2
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front2_LkList(ElemType arr[], int length);


///头插法建立
///返回值:链表的头指针,arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Front3_LkList(ElemType arr[], int length);


///插入元素:在指定的位置插入给定的值
//ptr:带插入的元素位置,将在ptr的后继结点中插入,x:插入的值
void Insert_After_LkList(LinkListNode* ptr, ElemType x);


///指定位置之前插入
///pHead:链表的头指针,ptr:带插入的元素位置,x:插入的值
void Insert_Before_LkList(LinkListNode* pHead, LinkListNode* ptr, ElemType x);


///删除节点:Ptr是需要删除的节点,将删除ptr的后续节点
///返回值是带删除的节点位置
LinkListNode* Delete_After_LkList(LinkListNode* ptr);


///删除第i个节点
///返回值是带删除的节点位置,pHead:头节点,i是第i个元素
LinkListNode* Delete_i_LkList(LinkListNode* pHead, int i);


///遍历
void ShowLkList(LinkListNode* pHead);

LinkList.c

#include "LinkList.h"

/*
1)    初始化:给线性表中的相关参数赋值
2)    求长度:求线性表中的元素的个数
3)    取元素:取给定位置的元素值
4)    查元素:查找给定元素值的位置
5)    插入元素:在指定的位置插入给定的值
6)    删除:删除指定位置的值或者是删除给定的值。
7)    遍历元素:从头到尾扫描线性表。

*/

///创建带有头节点的链表Init
LinkListNode* InitLinkList(void) 
{
    LinkListNode* pHead = NULL;
    pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
    if (pHead) {
        pHead->pNext = NULL; //链表的最后一个结点next值为空
    }
    return pHead;
}
//求长度:求线性表中的元素的个数
int GetSizeLinkList(LinkListNode* pHead) 
{
    int n = 0;
    while (pHead->pNext) 
    {
        n++;
        pHead = pHead->pNext;
    }
    return n;
}

//取元素:取给定位置的元素值
//输入链表的头指针,要查找的编号,输出第pos个元素的地址
///pHead:头指针,pos 待查节点的序号
LinkListNode* GetLinkListNode(LinkListNode* pHead, int pos) 
{
    int j = 0;
    LinkListNode* p;
    p = pHead;

    //带头结点是在链表最前面的位置,不属于链表
    if(pos == 0)
        return NULL;
    
    while (j < pos && p->pNext != NULL) 
    {
        p = p->pNext;
        j++;
    }
    
    if (pos == j)
        return p;
    else
        return NULL;
}

//查元素:查找给定元素值的位置
///找到就返回节点的地址,找不到就返回NULL
LinkListNode* LocateLinkList(LinkListNode* pHead, int objData) 
{
    LinkListNode* p;
    p = pHead->pNext;//跳过头节点
    while (p != NULL && p->data != objData) 
    {
        p = p->pNext;
    }
    return p;

}


//因为链表这种结构的内存是由程序员管理的,因此它的建立有一定的运算方法
///尾插法建立单链表
//arr:传入的顺序表,length:顺序表的长度
LinkListNode* Create_Rear_LkList(ElemType arr[], int length) 
{
    LinkListNode* pHead, *p, *q;
    int i;//循环变量,用来遍历全部的顺序表

    pHead = (LinkListNode*)malloc(sizeof(LinkListNode));//头结点

    //q是获得了当前链表的头节点
    //q保存了pHead,同时通过q不断前移使得链表串联起来
    q = pHead; 
    
    for (i = 0;i < length;i++) 
    {
        //获得一个单链表的节点,将这个节点加入到有pHead指向的这个链表当中
        //p获得一个可以加入链表的节点单元
        p = (LinkListNode*)malloc(sizeof(LinkListNode));
        p->data = arr[i];//将顺序表的内容存入单链表的节点

        q->pNext = p;//pHead一直指向链表头结点是不变的,通过q不断前移来串联链表
        q = p;
    }
    p->pNext = NULL;
    return pHead;

}

///头插法建立单链表,在head与head->next之间不断插入新申请结点
LinkListNode* Create_Front1_LkList(ElemType arr[], int length) 
{
    LinkListNode* pHead, *p, *q;
    int i;
    pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
    pHead->pNext = NULL; //有头结点的空链表
    q = pHead->pNext;
    //头插的时候,必须逆序遍历顺序表
    for (i = length - 1;i >= 0;i--) 
    {
        p = (LinkListNode*)malloc(sizeof(LinkListNode));
        p->data = arr[i];
        
        p->pNext = q;//是的新加入的节点传入了上一个节点
        pHead->pNext = p;//头节点指向了当前的新加入节点
        q = pHead->pNext;//让q指向当前的节点
    }
    return pHead;
}
///头插法2
LinkListNode* Create_Front2_LkList(ElemType arr[], int length) {
    LinkListNode* pHead, *p, *q;
    //p是新加入节点,q是当前节点
    int i;
    q = NULL;
    for (i = length - 1;i >= 0;i--) 
    {
        p = (LinkListNode*)malloc(sizeof(LinkListNode));
        p->data = arr[i];
        p->pNext = q;
        q = p;
    }
    pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
    pHead->pNext = q;
    return pHead;
}

///头插法建立
LinkListNode* Create_Front3_LkList(ElemType arr[], int length) 
{
    LinkListNode* pHead, *p;
    int i;
    pHead = (LinkListNode*)malloc(sizeof(LinkListNode));
    pHead->pNext = NULL;
    for (i = length - 1;i >= 0;i--) 
    {
        p = (LinkListNode*)malloc(sizeof(LinkListNode));
        p->data = arr[i];
        p->pNext = pHead->pNext;
        pHead->pNext = p; //pHead没有变化,pHead->pnext是不断变化的,始终作为当前节点的指针
    }
    //之所以我们的方法三可以节省方法一中的一个变量q
    //原因是:pHead不发生变化,而pHead中的pNext始终作为当前节点的指针
    //实际应用中采用的就是方法3
    return pHead;
}

/*
顺序表:12,33,44,76,89,90(逻辑上的顺序表)=>单链表
本例中,我们用数组表示这种顺序表
*/


//插入元素:在指定的位置插入给定的值
//在指定位置之后插入
void Insert_After_LkList(LinkListNode* ptr, ElemType x) 
{
    LinkListNode* s;
    s = (LinkListNode*)malloc(sizeof(LinkListNode));
    s->data = x;
    s->pNext = ptr->pNext; //ptr代表当前结点, ptr->pNext代表当前结点的下一个结点
    ptr->pNext = s;        //s代表带插入结点
}

//指定节点之前插入
void Insert_Before_LkList(LinkListNode* pHead, LinkListNode* ptr, ElemType x) 
{
    LinkListNode* s, *qPtr;
    s = (LinkListNode*)malloc(sizeof(LinkListNode));
    s->data = x;
    qPtr = pHead;//qPtr是用来代替pHead的移动的,ptr是目标节点
    while (qPtr->pNext != ptr)
    {
        qPtr = qPtr->pNext; //后移结点指针!!!
    }
    /*退出循环时候qPtr->pNext == ptr*/    
    s->pNext = ptr;
    qPtr->pNext = s;
    //因为链表是单向的,虽然我知道当前节点是ptr
    //但是在语法层面上,我如果想知道ptr的前继节点只能从head遍历而来
    //查到了当前节点的前继,才能使用后插的方法完成节点的加入
}


//删除:删除指定位置的值或者是删除给定的值。
//情形一:删除指定节点的后继结点
//情形二:删除第i个节点,假定头节点i=0

///删除指定节点ptr的后续节点
LinkListNode* Delete_After_LkList(LinkListNode* ptr) 
{
    LinkListNode* fptr;
    //假定我们的顺序表A-》B-》C,我们要删除的是A的后续节点B,A-》C
    fptr = ptr->pNext;// ptr是A,所以ptr的next是B,所以fptr是B
    ptr->pNext = fptr->pNext;//ptr是A,fptr是B,所以fptr的next是C,所以ptr-next就变成C
    return fptr;
}

///删除第i个节点
LinkListNode* Delete_i_LkList(LinkListNode* pHead, int i) 
{
    LinkListNode*ptr, *qPtr = NULL;
    ptr = GetLinkListNode(pHead, i - 1);//找到i的前继节点
    if (ptr != NULL && ptr->pNext != NULL)
        qPtr = Delete_After_LkList(ptr);
    return qPtr;
}

//遍历
void ShowLkList(LinkListNode* pHead) 
{
    LinkListNode* p = pHead->pNext; //跳过链表头结点,从链表第一个结点开始打印
    while (p != NULL) 
    {
        printf(" %d", p->data);
        p = p->pNext;
    }
}

main.c测试接口

#include "LinkList.h"

int main(void) 
{
    ElemType MySeq[] = { 1,2,3,4,5 };

    LinkListNode* pHead = Create_Rear_LkList(MySeq, 5);
    printf("\n********显示当前单链表中的全部元素******\n");
    ShowLkList(pHead);

    LinkListNode* pPos = GetLinkListNode(pHead, 2);
    Insert_After_LkList(pPos, 999);
    printf("\n********显示当前单链表中的全部元素******\n");
    ShowLkList(pHead);

    Insert_Before_LkList(pHead, pPos, 666);
    printf("\n********显示当前单链表中的全部元素******\n");
    ShowLkList(pHead);

    //Delete_After_LkList(pPos);
    Delete_i_LkList(pHead, 2);
    printf("\n********显示当前单链表中的全部元素******\n");
    ShowLkList(pHead);

    printf("\nList Size:%d", GetSizeLinkList(pHead));
    getchar();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值