数据结构之链表

数据结构之链表

最近,本学期陆陆续续学习了数据结构,学习了链表,栈,队列,二叉树。接下来,本段时间我会陆陆续续整理我本学期的笔记。小白一枚,写的不好很正常,部分也参考了别人的代码。
本节我会分成两个部分,一是线性表,而是顺序表。
首先我先讲讲线性表。
线性表不用多说了吧,简单说,就是先定义一个结构体,里面含有一个数据域,指针域。每个结点之间通过指针域进行连接。

顺序表和线性表的区别

什么是顺序表,和线性表差别在哪里?
简单来说,顺序表就是一个数组,也称为静态链表。顺序表在内存中,就是在连续的一段内存中存在,线性表在内存中则是零散分布的。那么线性表零散的内存是靠什么连接的呢,很简单,就是针指。每一个结点都会有一个数据域和指针域,就像一根线,将内存中的各个部分串联起来,访问了一个,根据这根线索,我们就可以访问下一个。
静态链表表面上没有用到针指,但是实际上从某种角度也实现了指针。顺序链表的每一个元素都由一个数据data,和一个下标cur组成(其实就相当于线性表的指针域)。静态链表相比于线性表,优点是插入和删除时,只需要删除游标,不需要移动元素。但是顺序链表很难解决长度的问题,多了浪费,少了不够。所以现实中,我们用的比较多的还是线性表。静态链表的话,我暂时还没写,如果有机会,以后我会补充。

单向线性表

我的LinkedList主要包括了几个功能,结点的插入,链表的初始化,链表的销毁,删除结点,遍历链表,查找结点,反转链表,判断是否成环,链表的结点两两进行交换,查找中间结点。
下面是头文件 linkedList.h,大家稍微看看即可,重心主要放在LinkedList.c
对了,这里为了方便管理,我们采用了二重指针的形式,就是一个有一个指针指向头节点。
在这里插入图片描述

头文件

#include<stdio.h>
#define OK 1
#define FALSE 0
/***************************************************************************************
 *	File Name				:	linkedList.h
 *	CopyRight				:	Chris
 *	SYSTEM					:   win10
 *	Create Data				:	2020.3.28
 *
 *
 *--------------------------------Revision History--------------------------------------
 *	No	version		Data			Revised By			Item			Description
 *
 *
 ***************************************************************************************/

 /**************************************************************
*	Multi-Include-Prevent Section
**************************************************************/
#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED

/**************************************************************
*	Macro Define Section
**************************************************************/

#define OVERFLOW -1

/**************************************************************
*	Struct Define Section
**************************************************************/

// define element type
typedef int ElemType;

// define struct of linked list
typedef struct LNode {
	ElemType data;
  	struct LNode *next;
} LNode, *LinkedList;

// define Status
typedef enum Status {
	ERROR,
	SUCCESS
} Status;
/**************************************************************
*	Prototype Declare Section
**************************************************************/
void pf(ElemType e);
/**
 *  @name        : Status InitList(LinkList *L);
 *	@description : initialize an empty linked list with only the head node without value
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status InitList(LinkedList *L);

/**
 *  @name        : void DestroyList(LinkedList *L)
 *	@description : destroy a linked list, free all the nodes
 *	@param		 : L(the head node)
 *	@return		 : None
 *  @notice      : None
 */
void DestroyList(LinkedList *L);

/**
 *  @name        : Status InsertList(LNode *p, LNode *q)
 *	@description : insert node q after node p
 *	@param		 : p, q
 *	@return		 : Status
 *  @notice      : None
 */
Status InsertList(LNode *p, LNode *q);

/**
 *  @name        : Status DeleteList(LNode *p, ElemType *e)
 *	@description : delete the first node after the node p and assign its value to e
 *	@param		 : p, e
 *	@return		 : Status
 *  @notice      : None
 */
Status DeleteList(LNode *p, ElemType *e);

/**
 *  @name        : void TraverseList(LinkedList L, void (*visit)(ElemType e))
 *	@description : traverse the linked list and call the funtion visit
 *	@param		 : L(the head node), visit
 *	@return		 : None
 *  @notice      : None
 */
void TraverseList(LinkedList L, void (*visit)(ElemType e));

/**
 *  @name        : Status SearchList(LinkedList L, ElemType e)
 *	@description : find the first node in the linked list according to e
 *	@param		 : L(the head node), e
 *	@return		 : Status
 *  @notice      : None
 */
Status SearchList(LinkedList L, ElemType e);

/**
 *  @name        : Status ReverseList(LinkedList *L)
 *	@description : reverse the linked list
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status ReverseList(LinkedList *L);

/**
 *  @name        : Status IsLoopList(LinkedList L)
 *	@description : judge whether the linked list is looped
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status IsLoopList(LinkedList L);

/**
 *  @name        : LNode* ReverseEvenList(LinkedList *L)
 *	@description : reverse the nodes which value is an even number in the linked list, input: 1 -> 2 -> 3 -> 4  output: 2 -> 1 -> 4 -> 3
 *	@param		 : L(the head node)
 *	@return		 : LNode(the new head node)
 *  @notice      : choose to finish
 */
LNode* ReverseEvenList(LinkedList *L);

/**
 *  @name        : LNode* FindMidNode(LinkedList *L)
 *	@description : find the middle node in the linked list
 *	@param		 : L(the head node)
 *	@return		 : LNode
 *  @notice      : choose to finish
 */
LNode* FindMidNode(LinkedList *L);

/**
 *  @name        : CreateList(LinkedList* L, int n)
 *	@description : Create a random list
 *	@param		 : L(the head node), n(num of the Node)
 *	@return		 : None
 *  @notice      : None
 */
void CreateList(LinkedList* L, int n);


 /**************************************************************
*	End-Multi-Include-Prevent Section
**************************************************************/
#endif

源文件

#include "linkedList.h"



/**
 *  @name        : Status InitList(LinkList *L);
 *	@description : initialize an empty linked list with only the head node without value
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */

Status InitList(LinkedList *L) {
    *L = (LinkedList)malloc(sizeof(LNode));
    (*L)->next = NULL;
    return OK;
}

/**
 *  @name        : void DestroyList(LinkedList *L)
 *	@description : destroy a linked list, free all the nodes
 *	@param		 : L(the head node)
 *	@return		 : None
 *  @notice      : None
 */
void DestroyList(LinkedList *L) {
    LinkedList p, s;
    p = (*L)->next;
    while (p)
    {
        s = p->next;
        free(p);
        p = s;
    }
    (*L)->next = NULL;
    return SUCCESS;
}

/**
 *  @name        : Status InsertList(LNode *p, LNode *q)
 *	@description : insert node q after node p
 *	@param		 : p, q
 *	@return		 : Status
 *  @notice      : None
 */
Status InsertList(LNode *p, LNode *q) {
    if (p == NULL || q == NULL)
        return ERROR;
    q->next = p->next;
    p->next = q;
    return SUCCESS;
}
/**
 *  @name        : Status DeleteList(LNode *p, ElemType *e)
 *	@description : delete the first node after the node p and assign its value to e
 *	@param		 : p, e
 *	@return		 : Status
 *  @notice      : None
 */
Status DeleteList(LNode *p, ElemType *e) {
    LinkedList r;
    r = p->next;
    p->next = p->next->next;
    *e = r->data;
    free(r);
    return SUCCESS;
}

/**
 *  @name        : void TraverseList(LinkedList L, void (*visit)(ElemType e))
 *	@description : traverse the linked list and call the funtion visit
 *	@param		 : L(the head node), visit
 *	@return		 : None
 *  @notice      : None
 */
void TraverseList(LinkedList L, void (*visit)(ElemType e)) {
   LinkedList p = L->next;
    while (p) {
        visit(p->data);
        p = p->next;
    }
    printf("\n");
}

void pf(ElemType e) {
    printf("%d ", e);
}

/**
 *  @name        : Status SearchList(LinkedList L, ElemType e)
 *	@description : find the first node in the linked list according to e
 *	@param		 : L(the head node), e
 *	@return		 : Status
 *  @notice      : None
 */
Status SearchList(LinkedList L, ElemType e) {
    LinkedList p;
    p = L->next;
    while(p)
    {
        if (p->data == e)
            return SUCCESS;
        p = p->next;
    }
    return ERROR;
}

/**
 *  @name        : Status ReverseList(LinkedList *L)
 *	@description : reverse the linked list
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status ReverseList(LinkedList *L) {
    LinkedList p,r, q;
    p = NULL;
    r = (*L)->next;
    q = r->next;
    if (r == NULL || q == NULL)/*判断是否为空表或者只有一个节点*/
        return;
    while (q) {
        r->next = p; 
        p = r;       
        r = q;       
        q = q->next;
    }
    r->next = p;     
    (*L)->next = r;  
    printf("\n");
    return SUCCESS;
}

/**
 *  @name        : Status IsLoopList(LinkedList L)
 *	@description : judge whether the linked list is looped
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status IsLoopList(LinkedList L) {
    if (L == NULL || L->next == NULL)
        return ERROR;
    LinkedList fast,  slow;
    fast = L->next->next;
    slow = L->next;
    while (1) {
        if (!fast || !slow)
            return ERROR;
        if (fast == slow)
            return SUCCESS;
        else {
            fast = fast->next->next;
            slow = slow->next;
        }
    }
}

/**
 *  @name        : LNode* ReverseEvenList(LinkedList *L)
 *	@description : reverse the nodes which value is an even number in the linked list, input: 1 -> 2 -> 3 -> 4  output: 2 -> 1 -> 4 -> 3
 *	@param		 : L(the head node)
 *	@return		 : LNode(the new head node)
 *  @notice      : choose to finish
 */
LNode* ReverseEvenList(LinkedList* L) {
    LinkedList dummyHead = (LinkedList)malloc(sizeof(LNode));//创建虚拟结点
    dummyHead->next = (*L)->next;//虚拟结点的next指向联保第一个结点
    LinkedList cur = dummyHead;
    while (cur->next != NULL && cur->next->next != NULL) {
        LinkedList tmp = cur->next; // 记录临时节点
        LinkedList tmp1 = cur->next->next->next; // 记录临时节点

        cur->next = cur->next->next;    // 步骤一
        cur->next->next = tmp;          // 步骤二
        cur->next->next->next = tmp1;   // 步骤三

        cur = cur->next->next; // cur移动两位,准备下一轮交换
    }
    LinkedList p = dummyHead->next;
    free(dummyHead);
    return p;
}

/**
 *  @name        : LNode* FindMidNode(LinkedList *L)
 *	@description : find the middle node in the linked list
 *	@param		 : L(the head node)
 *	@return		 : LNode
 *  @notice      : choose to finish
 */
LNode* FindMidNode(LinkedList* L) {
    LinkedList fast, slow, p;
    fast = *L;
    slow = *L;

    while (fast && fast->next)
    {
        p = slow;
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

void CreateList(LinkedList* L, int n)
{
    srand(time(0));//初始化随机种子
    int i;
    *L = (LinkedList)malloc(sizeof(LNode));
    (*L)->next = NULL;
    LinkedList p;
    for (i = 0; i < n; i++)
    {
        p = (LinkedList)malloc(sizeof(LNode));
        p->data = rand() % 100 + 1;//生成1-100的随机数;
        p->next = (*L)->next;
        (*L)->next = p;
    }
}
void Display(LinkedList* L)//打印链表
{
    LinkedList p;
    p = (*L)->next;
    while (p)
    {
        printf("%d  ", p->data);
        p = p->next;
    }
    printf("\n");
}

前面的大部分功能都挺简单,不细讲,主要讲我当时觉得写起来有困难的部分。判断是否成环,就是类似于中学学习的追击问题。我们可以多设置一个指针,已两倍的速度行走,就是每次移动两次,p=p->next->next,到最后我们如果此指针与正常遍历的指针相遇,即成环。找到中间结点也是一样,我们也是用两个指针,一快一慢,快的二倍速行走,当快的指针走到末尾,那么慢的指针指向的就是中间结点。
好了,到了我认为最难的部分,ReverseEvenList,结点间两两进行交换,首先,我们需要创造一个虚拟的结点。
在这里插入图片描述
大概画了画原理图(丑了点,凑合看),就是cur结点先指向结点2,然后结点2又指向结点1,结点1最后指向结点1,可以看到,1、2已经交换完成,这只是一次循环。对了,最后别忘记free掉虚拟结点。
还有一个有趣的是,是遍历链表,我们看看这个函数,void TraverseList(LinkedList L, void (*visit)(ElemType e)),本人菜鸡一枚,上课没认真听老师讲指针,居然漏了函数指针这个东西。对于遍历链表,我们每一次遍历可能都会有不同的操作,例如本次只是简单打印一下结点的值。为了方便,不必重复修改代码,我们采用了函数指针。函数指针,顾名思义就是一个指向函数的指针。在该遍历函数的调用中,我们可以传入一个有打印功能的函数,那么遍历该链表时,我们对每一个结点的操作就是打印该结点的内容。当然也可以换成其他的。

双向线性表

对于双向链表,实现的功能比单向的少一点,概念了解就行。

头文件

#include "duLinkedList.h"
#include "malloc.h"
/**
 *  @name        : Status InitList_DuL(DuLinkedList *L)
 *	@description : initialize an empty linked list with only the head node
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status InitList_DuL(DuLinkedList *L) {
    *L = (DuLinkedList)malloc(sizeof(DuLNode));
	(*L)->next = NULL;
	(*L)->prior = NULL;
    (*L)->data = NULL;
	return SUCCESS;
}

/**
 *  @name        : void DestroyList_DuL(DuLinkedList *L)
 *	@description : destroy a linked list
 *	@param		 : L(the head node)
 *	@return		 : status
 *  @notice      : None
 */
void DestroyList_DuL(DuLinkedList *L) {
    DuLinkedList p;
    while (*L) 
    {
        p = (*L)->next;
        free(*L);
        *L = p;
        if (p)
            p->prior = NULL;
    }
    return SUCCESS;
	
}

/**
 *  @name        : Status InsertBeforeList_DuL(DuLNode *p, LNode *q)
 *	@description : insert node q before node p
 *	@param		 : p, q
 *	@return		 : status
 *  @notice      : None
 */
Status InsertBeforeList_DuL(DuLNode *p, DuLNode *q) {
    if (!p)
        return ERROR;
    if (p->prior) {
        p->prior->next = q;
        q->prior = p->prior;
    }
    q->next = p;
    p->prior = q;
    return SUCCESS;
}

/**
 *  @name        : Status InsertAfterList_DuL(DuLNode *p, DuLNode *q)
 *	@description : insert node q after node p
 *	@param		 : p, q
 *	@return		 : status
 *  @notice      : None
 */
Status InsertAfterList_DuL(DuLNode *p, DuLNode *q) {
    if (p->next == NULL&&p->prior==NULL)
    {
        q->prior = NULL;
        q->next = p;
        p->prior = q;
    }
    else
    {
        q->next = p->next;
        q->prior = p;
        p->next->prior = q;
        p->next = q;
    }
    return SUCCESS;
}

/**
 *  @name        : Status DeleteList_DuL(DuLNode *p, ElemType *e)
 *	@description : delete the first node after the node p and assign its value to e
 *	@param		 : p, e
 *	@return		 : status
 *  @notice      : None
 */
Status DeleteList_DuL(DuLNode *p, ElemType *e) {
    *e = p->next->data;
    p = p->next;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return SUCCESS;
}

/**
 *  @name        : void TraverseList_DuL(DuLinkedList L, void (*visit)(ElemType e))
 *	@description : traverse the linked list and call the funtion visit
 *	@param		 : L(the head node), visit
 *	@return		 : Status
 *  @notice      : None
 */
void TraverseList_DuL(DuLinkedList L, void (*visit)(ElemType e)) {
    DuLinkedList p = L;
        while (p) {
            visit(p->data);
            p = p->next;
        }
        printf("\n");
    
}
void pf(ElemType e) {
    printf("%d  ", e);
}

void Display(DuLinkedList * L)//打印链表
{
    DuLinkedList p = *L;
    do {
        if (p == NULL)
        {
            printf("The list is empty\n");
            break;
        }
            
        printf("%d ", p->data);
        p = p->next;
    } while (p);
    printf("\n");
}
void CreateList(DuLinkedList *L)
{
     
     srand(time(0));//初始化随机种子
     for (int i = 0; i < 5; i++)
     {
         DuLinkedList r = (DuLinkedList)malloc(sizeof(DuLNode));
         r->prior = NULL;
         r->data= rand() % 100 + 1;//生成1-100的随机数;
         DuLinkedList p = *L;
         r->next = p;
         p->prior = r;
         *L = r;
     }

}

源文件

#include "duLinkedList.h"
#include "malloc.h"
/**
 *  @name        : Status InitList_DuL(DuLinkedList *L)
 *	@description : initialize an empty linked list with only the head node
 *	@param		 : L(the head node)
 *	@return		 : Status
 *  @notice      : None
 */
Status InitList_DuL(DuLinkedList *L) {
    *L = (DuLinkedList)malloc(sizeof(DuLNode));
	(*L)->next = NULL;
	(*L)->prior = NULL;
    (*L)->data = NULL;
	return SUCCESS;
}

/**
 *  @name        : void DestroyList_DuL(DuLinkedList *L)
 *	@description : destroy a linked list
 *	@param		 : L(the head node)
 *	@return		 : status
 *  @notice      : None
 */
void DestroyList_DuL(DuLinkedList *L) {
    DuLinkedList p;
    while (*L) 
    {
        p = (*L)->next;
        free(*L);
        *L = p;
        if (p)
            p->prior = NULL;
    }
    return SUCCESS;
	
}

/**
 *  @name        : Status InsertBeforeList_DuL(DuLNode *p, LNode *q)
 *	@description : insert node q before node p
 *	@param		 : p, q
 *	@return		 : status
 *  @notice      : None
 */
Status InsertBeforeList_DuL(DuLNode *p, DuLNode *q) {
    if (!p)
        return ERROR;
    if (p->prior) {
        p->prior->next = q;
        q->prior = p->prior;
    }
    q->next = p;
    p->prior = q;
    return SUCCESS;
}

/**
 *  @name        : Status InsertAfterList_DuL(DuLNode *p, DuLNode *q)
 *	@description : insert node q after node p
 *	@param		 : p, q
 *	@return		 : status
 *  @notice      : None
 */
Status InsertAfterList_DuL(DuLNode *p, DuLNode *q) {
    if (p->next == NULL&&p->prior==NULL)
    {
        q->prior = NULL;
        q->next = p;
        p->prior = q;
    }
    else
    {
        q->next = p->next;
        q->prior = p;
        p->next->prior = q;
        p->next = q;
    }
    return SUCCESS;
}

/**
 *  @name        : Status DeleteList_DuL(DuLNode *p, ElemType *e)
 *	@description : delete the first node after the node p and assign its value to e
 *	@param		 : p, e
 *	@return		 : status
 *  @notice      : None
 */
Status DeleteList_DuL(DuLNode *p, ElemType *e) {
    *e = p->next->data;
    p = p->next;
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return SUCCESS;
}

/**
 *  @name        : void TraverseList_DuL(DuLinkedList L, void (*visit)(ElemType e))
 *	@description : traverse the linked list and call the funtion visit
 *	@param		 : L(the head node), visit
 *	@return		 : Status
 *  @notice      : None
 */
void TraverseList_DuL(DuLinkedList L, void (*visit)(ElemType e)) {
    DuLinkedList p = L;
        while (p) {
            visit(p->data);
            p = p->next;
        }
        printf("\n");
    
}
void pf(ElemType e) {
    printf("%d  ", e);
}

void Display(DuLinkedList * L)//打印链表
{
    DuLinkedList p = *L;
    do {
        if (p == NULL)
        {
            printf("The list is empty\n");
            break;
        }
            
        printf("%d ", p->data);
        p = p->next;
    } while (p);
    printf("\n");
}
void CreateList(DuLinkedList *L)
{
     
     srand(time(0));//初始化随机种子
     for (int i = 0; i < 5; i++)
     {
         DuLinkedList r = (DuLinkedList)malloc(sizeof(DuLNode));
         r->prior = NULL;
         r->data= rand() % 100 + 1;//生成1-100的随机数;
         DuLinkedList p = *L;
         r->next = p;
         p->prior = r;
         *L = r;
     }

}

双向链表我们主要是要注意有两个指针,插入修改删除都有些不一样,一定要注意指针。双向链表的实现其实也差不多,我就不画图了(懒)。
大一新生一枚,代码可能有很多出错且不严谨的地方,仅供参考。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值