单向链表的链式实现

Note

  • 使用的工具是CodeBlocks 16.01
  • 启用了C99标准
单向链表的链式实现_第1张图片
CodeBlocks启用C99支持

单向链表是这样是个序列:对于单向链表中的某一个元素ai,ai.data保存了ai的值,ai.pointer保存了ai+1的地址,最后一个Node的pointer为NULL。

单向链表的链式实现_第2张图片
单向链表的一个Node模型
单向链表的链式实现_第3张图片
一个单向链表模型

如果我们得到了第一Node的地址或第一个Node变量,我们就可以访问到所有的Node。

Node结构体的声明如下:

// node.c
typedef struct node{
  int data;
  struct node* pointer;
}Node;

有了Node的模型,我们怎样创建一个单向链表呢?我们可以创建一个个的Node,然后把它们连接起来,如下所示:

// node.c
typedef struct node{
  int data;
  struct node* pointer;
}Node;

int main(void)
{
  Node n1,n2,n3,n4,n5,n6,n7; // 创建n1~n7共7个Node

  //把n1~n7连接起来
  n1.pointer = &n2;
  n2.pointer = &n3;
  n3.pointer = &n4;
  n4.pointer = &n5;
  n5.pointer = &n6;
  n6.pointer = &n7;
  n7.pointer = NULL; //n7是最后一个Node,其pointer为NULL

  //在n1~n7中存储数据
  n1.data = 1;
  n2.data = 2;
  n3.data = 3;
  n4.data = 4;
  n5.data = 5;
  n6.data = 6;
  n7.data = 7;

  return 0;
}

使用上面的代码,我们创建了一个具有7个元素的单向链表,其结构图如下:

单向链表的链式实现_第4张图片
Paste_Image.png

使用上面的方法,我们完全可以创建一个可以保存很多元素的单向链表,只要我们声明一个Node,并且把它添加到链表中即可。例如,如果我们还有添加一个元素n8,我们可以这样做:

Node n8;
n8.data = 8;
n8.pointer = NULL;
n7.pointer = &n8;

使用这种方式,我们可以很方便第知道自己的单向链表有多少个元素;可以很方便第访问其中的任一个元素;可以很方便的添加、删除元素。但是使用这种方法也有缺点:

  • 每次都要创建一个节点,然后为其赋值,并将其添加到单向链表的末尾。
  • 如果需要添加的元素成百上千,我们就需要创建成百上千的Node变量,很麻烦。

因此,如果可以有一个函数,我们提供给他第一个Node或者最后一个Node的地址和需要添加的元素的值,它就可以帮我们创建一个节点,并为节点赋值,将节点添加到单向链表的末尾,岂不是一个好事?!因此,我打算写一个函数append(Node * pNode,int data),它接收第一个Node的地址(通过第一个Node,我们可以找到所有的Node)和需要添加的元素值data。

bool append(Node*pNode,int data)
{
  Node * pEnd = pNode; // 保存最后一个元素的地址
  while(pEnd->pointer!=NULL){ 
    pEnd = pEnd->pointer; // 让pEnd保存下一个Node的地址,直到pEnd保存了最后一个Node的地址
  }
  
  // 创建一个新的Node
  Node *pNew = (Node *)malloc(sizeof(Node));
  if(pNew==NULL){
    printf("内存分配失败!\n");
    exit(-1);
  }
  
 // 保存元素;将新创建的Node变为最后一个Node;将新创建的Node和其他的Node连接起来
  pNew->data = data;
  pNew->pointer = NULL;
  pEnd->pointer = pNew;
  return true;
}

我们写了上面的append(Node * pNode,int data)函数后,我们就可以像这样往单向链表中添加元素了。

//node.c
#include
#include
#include

typedef struct node{
  int data;
  struct node * pointer;
}Node;

bool append(Node*pNode,int data)
{
  Node * pEnd = pNode; // 保存最后一个元素的地址
  while(pEnd->pointer!=NULL){ 
    pEnd = pEnd->pointer; // 让pEnd保存下一个Node的地址,直到pEnd保存了最后一个Node的地址
  }
  
  // 创建一个新的Node
  Node *pNew = (Node *)malloc(sizeof(Node));
  if(pNew==NULL){
    printf("内存分配失败!\n");
    exit(-1);
  }
  
 // 保存元素;将新创建的Node变为最后一个Node;将新创建的Node和其他的Node连接起来
  pNew->data = data;
  pNew->pointer = NULL;
  pEnd->pointer = pNew;
  return true;
}

int main(void)
{
  // 先创建第一个Node,因为append(Node*pNode,int data)需要第一个Node的地址。
  Node n1;
  n1.data = 1;
  n1.pointer = NULL;

  append(&n1,2);
  append(&n1,3);
  append(&n1,4);
  append(&n1,5);
  append(&n1,6);
  append(&n1,7);
  append(&n1,8);
  
  //输出
  Node *pEnd = &n1;
  while(pEnd->pointer!=NULL){ // 如果pEnd保存的不是最后一个元素的地址
    printf("%d ",pEnd->data);
    pEnd = pEnd->pointer;
  }
  // 循环结束后,pEnd保存的是最后一个元素的地址
  printf("%d \n",pEnd->data);//输出最后一个元素的值
  return 0;
}

到现在为止,似乎没有什么问题。现在我想写一个函数,求单向链表的长度。我们知道通过第一个节点的地址,我们可以找到所有节点,因此函数需要第一个Node的地址作为参数:

int len(Node*pNode){
  int len = 1; //这里设置了初始值为1,因为我们传递过来的第一个节点是有值的
  Node*pEnd = pNode;
  while(pEnd->pointer!=NULL){
    len++;
    pEnd = pEnd->pointer;
  }
  return len;
}

发现没有,似乎我们的单向链表的长度永远不可能为0啊!我们也无法清空我的单向链表,因为其长度最少都是1。怎么办呢?这就需要在第一个节点的前面引入另一个节点,这个节点的data中不保存数据,pointer则指向我们存储数据的第一个节点。这样可以方便我们创建空的单向链表,清空链表,在第一个存储数据的节点前插入节点。

  • 我们在第一个存储数据的Node前插入的节点又叫头节点
  • 存储头结点地址的变量叫头指针
  • 第一个存储数据的节点叫首节点

Note头节点的data中并没有存储数据;头节点的pointer存储了首节点的地址;如果头节点的pointer为NULL,则说明单向链表为空。

一些术语

知道这些东西后,我们就可以编写操作单向链表的函数了。如下:linked_list.h中定义了单向链表的结构体和可以对其进行操作的函数。

linked_list.h

#include

typedef struct node{
    struct node * pNext; // 指针域:指向下一个元素的指针
    int element; // 数据域:保存元素值
}Node,LinkedList; // 给struct node数据类型起了两个别名Node,LinkedList
// LinkedList别名倾向于表示整个的单向链表
// Node别名倾向于表示单向链表中的节点

void linkedListInit(Node * pNode); // 初始化单向链表
void linkedListShow(const LinkedList * const pList);//显示单向链表中的所有元素
bool linkedListEmpty(const LinkedList * const pList);//判断单向链表是否为空
bool linkedListAppend(LinkedList*pList,int e);//在单向链表的末尾追加元素
bool linkedListInsert(LinkedList*pList,int i,int e);//在单向链表的第i处插入元素
int linkedListLen(const LinkedList*const pList);//计算单向链表中有多少个元素
bool linkedListRemove(LinkedList*pLisy,int i,int*e);//移除单向链表中指定位置的元素
bool linkedListPop(LinkedList*pList,int*e);//弹出单向链表中最后一个元素
void linkedListSort(LinkedList*pList);//排序
bool linkedListContain(const LinkedList*const pList,int e);//判断单向链表中是否包含某个元素
bool linkedListGet(const LinkedList*const pList,int i,int *e);//得到单向链表中某一个位置的元素
int linkedListIndex(const LinkedList*const pList,int e);//得到元素e在单向链表中的索引
void linkedListClear(LinkedList*pList);//清空单向链表

linkedList.c是以上定义的函数的实现代码。

linkedList.c

#include
#include"linked_list.h"
#include

/** \brief 初始化LinkedList对象
 *
 * \param pNode Node* 指向LinkedList对象的指针
 * \return void
 *
 */
void linkedListInit(LinkedList * pList)
{
    pList->pNext=NULL; //让头结点的pointer为空,以创建一个空的单向链表;注意并没有为头结点的data赋值。
    return;
}

/** \brief 打印LinkedList对象的每一个元素
 *
 * \param pList const LinkedList*const LinkedList对象
 * \return void
 *
 */
void linkedListShow(const LinkedList*const pList)
{
    if(linkedListEmpty(pList)) // 如果单向链表为空
    {
        printf("LinkedList is empty!");
        return;
    }
    LinkedList* pTemp = pList->pNext;
    while(pTemp!=NULL)
    {
        printf("%d ",pTemp->element);
        pTemp = pTemp->pNext;
    }
    printf("\n");
    return;

}
/** \brief 判断LinkedList是否为空
 *
 * \param const LinkedList * const pList 判断是否为空的LinkedList对象
 * \return bool 如果为空则返回true,否则返回false
 *
 */
bool linkedListEmpty(const LinkedList * const pList)
{
    return pList->pNext==NULL;
}

/** \brief 向LinkedList末尾添加元素
 *
 * \param LinkedList*pList LinkedList对象
 * \param e int 添加的元素
 * \return bool 添加成功则返回true,否则返回false
 *
 */
bool linkedListAppend(LinkedList*pList,int e)
{
    Node* pNode = pList;
    while(pNode->pNext!=NULL)
    {
        pNode=pNode->pNext;
    }
    Node* pNew = (Node*)malloc(sizeof(Node));
    if(pNew==NULL)
    {
        printf("分配内存失败!\n");
        exit(-1);
    }
    pNew->element=e;
    pNew->pNext=NULL;
    pNode->pNext=pNew;
    return true;
}
/** \brief 在LinkedList的某一个位置i处插入元素e
 *
 * \param LinkedList*pList 指向LinkedList对象的指针
 * \param i int 插入元素的位置,从0开始
 * \param e int 被插入的元素e
 * \return bool 如果插入的位置不属于[0,len-1],则插入失败
 *
 */
bool linkedListInsert(LinkedList*pList,int i,int e)
{
    int len = linkedListLen(pList);
    if(i>=0 && ielement=e;
                pNew->pNext=pNode->pNext;
                pNode->pNext=pNew;
                return true;
            }
            pNode=pNode->pNext;
        }
    }
    return false;
}
/** \brief 获取LinkedList的长度
 *
 * \param pList const LinkedList*const 指向LinkedList对象的指针
 * \return int 长度
 *
 */
int linkedListLen(const LinkedList*const pList)
{
    int len = 0;
    Node* pNode = pList->pNext;
    while(pNode!=NULL)
    {
        pNode=pNode->pNext;
        len++;
    }
    return len;
}
/** \brief 从LinkedList中移除指定位置的元素
 *
 * \param LinkedList*pLisy 指向LinkedList对象的指针
 * \param i int 指定的位置,从0开始
 * \param int *e 保存被移除的元素
 * \return bool 如果LinkedList为空或者指定的位置不存在,则返回false。
 *
 */
bool linkedListRemove(LinkedList*pList,int i,int *e)
{
    if(linkedListEmpty(pList)){
        return false;
    }
    if(i<0){
        return false;
    }
    int len = linkedListLen(pList);
    if(i>=len){
        return false;
    }
    Node * pNode = pList;
    for(int index = 0; index < len; index++){
        if(index==i){
            Node*pTemp = pNode->pNext;
            *e = pTemp->element;
            pNode->pNext=pTemp->pNext;
            pTemp->pNext=NULL;
            free(pTemp);
            return true;
        }
        pNode=pNode->pNext;
    }
}
/** \brief 从LinkedList中弹出最后一个元素
 *
 * \param LinkedList*pList 指向LinkedList对象的指针
 * \param int *e 保存被弹出的元素
 * \return bool 如果LinkedList为空,则返回false
 *
 */
bool linkedListPop(LinkedList*pList,int *e)
{
    if(linkedListEmpty(pList)){
        return false;
    }
    int len = linkedListLen(pList);
    Node* pNode = pList->pNext;
    for(int index = 0; index < len-2; index++){
        pNode=pNode->pNext;
    }
    Node* pTemp = pNode->pNext;
    *e = pTemp->element;
    free(pTemp);
    pNode->pNext=NULL;
    return true;
}
/** \brief 对LinkedList进行排序
 *
 * \param LinkedList*pList 指向LinkedList对象的指针
 * \return void
 *
 */
void linkedListSort(LinkedList*pList)
{
    if(linkedListEmpty(pList))
    {
        printf("List is empty!\n");
        return;
    }
    Node* p1 = pList->pNext;
    Node* p2;
    if(p1->pNext!=NULL)
    {
        p2=p1->pNext;
    }
    while(p1!=NULL)
    {
        while(p2!=NULL)
        {
            if(p1->element>p2->element)
            {
                p1->element=p1->element^p2->element;
                p2->element=p1->element^p2->element;
                p1->element=p1->element^p2->element;
            }
            p2=p2->pNext;
        }
        if(p1->pNext==NULL){
            return;
        }else{
            p1 = p1->pNext;
        }

        if(p1->pNext==NULL){
            return;
        }else{
            p2=p1->pNext;
        }
    }
    return;
}

*/
/** \brief 判断LinkedList中是否包含元素e
 *
 * \param pList const LinkedList*const 指向LinkedList对象的指针
 * \param e int e元素
 * \return bool 如果包含,则返回true,否则返回false
 *
 */
bool linkedListContain(const LinkedList*const pList,int e)
{
    if(linkedListEmpty(pList))
    {
        return false;
    }
    Node*pNode = pList->pNext;
    while(pNode!=NULL)
    {
        if(pNode->element==e)
        {
            return true;
        }
        pNode=pNode->pNext;
    }
    return false;
}
/** \brief 获取指定索引处的元素
 *
 * \param pList const LinkedList*const 指向LinkedList对象的指针
 * \param i int 索引
 * \return bool 如果获取该元素在LinkedList中,则获取成功,否则获取失败
 *
 */
bool linkedListGet(const LinkedList*const pList,int i,int *e)
{
    if(linkedListEmpty(pList))
    {
        printf("LinkedList是空的!\n");
        return false;
    }
    int index=0;
    Node* pNode = pList->pNext;
    while(pNode!=NULL)
    {
        if(index==i)
        {
            *e=pNode->element;
            return true;
        }
        pNode=pNode->pNext;
        index++;
    }
    return false;
}
/** \brief 在LinkedList中查找某一个元素e索引,索引从0开始
 *
 * \param pList const LinkedList*const 指向LinkedList对象的指针
 * \param e int 查找的元素e
 * \return int 找到则返回e在LinkedList中的索引,否则返回-1
 *
 */
int linkedListIndex(const LinkedList*const pList,int e)
{
    if(linkedListEmpty(pList))
    {
        return -1;
    }
    int index = 0;
    Node* pNode = pList->pNext;
    while(pNode!=NULL)
    {
        if(pNode->element==e)
        {
            return index;
        }
        pNode=pNode->pNext;
        index++;
    }
    return -1;
}
/** \brief 清空LinkedList
 *
 * \param LinkedList*pList 需要清空的LinkedList对象
 * \return void
 *
 */
void linkedListClear(LinkedList*pList)
{
    if(linkedListEmpty(pList))
    {
        return;
    }

    Node* pNode = pList->pNext;
    pList->pNext=NULL;

    Node* pTemp;
    while(pNode->pNext!=NULL)
    {
        pTemp=pNode->pNext;
        free(pNode);
        pNode=pTemp;
    }
    free(pNode);
    return;
}

测试代码

linkedListTest.c

#include"linked_list.h"
#include

int main(void)
{
    LinkedList myList,*pMyList;
    pMyList = &myList;
    linkedListInit(pMyList);
    linkedListAppend(pMyList,89);
    linkedListAppend(pMyList,90);
    linkedListAppend(pMyList,78);
    linkedListAppend(pMyList,82);
    linkedListAppend(pMyList,87);
    linkedListAppend(pMyList,60);

    linkedListShow(pMyList);

    printf("%d在LinkedList中的索引是:%d\n",90,linkedListIndex(pMyList,90));
    //linkedListClear(pMyList);
    linkedListShow(pMyList);
    int e;
    linkedListGet(pMyList,5,&e);
    printf("第%d个位置的元素是:%d\n",5,e);
    if(linkedListContain(pMyList,60)){
        printf("True\n");
    }else{
        printf("false\n");
    }
    printf("linkedList的长度是:%d\n",linkedListLen(pMyList));
    printf("------排序-----\n");
    linkedListSort(pMyList);
    //linkedListReverse(pMyList);

    linkedListShow(pMyList);

    printf("------删除-----\n");
    linkedListRemove(pMyList,5,&e);
    printf("%d\n",e);
    linkedListShow(pMyList);
    linkedListInsert(pMyList,0,12);
    linkedListInsert(pMyList,1,40);
    linkedListInsert(pMyList,5,88);
    linkedListInsert(pMyList,3,72);
    linkedListShow(pMyList);
    linkedListPop(pMyList,&e);
    linkedListShow(pMyList);
    return 0;
}

你可能感兴趣的:(单向链表的链式实现)