数据结构与算法分析-用C语言实现单链表

本文详细介绍了单链表数据结构的基本概念、声明与实现过程,包括链表节点结构、常用函数及其使用方法,通过实例代码加深读者对单链表的理解。

掌握单链表很容易,把下面的代码弄懂,敲几遍,全部记住,而且记清每一个细节。

首先,在List.h中声明单链表的ADT.我们把我们所需要的自定义类型啊,函数啊,都声明出来,但这里我们只是声明他们,而具体实现则是在List.c中进行。

/**
* @file    List.h
* @brief   单链表的声明
* @details
* @author   mrbourne@163.com
* @date     2014-5-19
*/
#ifndef _List_H

//先声明实现单链表时所需的类型和结构,包括一个节点结构体,元素类型,指向元素的指针类型(同样可以用来表示单链表本身和元素位置)
struct Node;
typedef int ElementType;    //此处根据链表中元素类型的不同 可以修改
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;

//接下来声明一些常用的函数,一定要记住这些函数,因为这些函数都是最常用最基础的
List MakeEmpty(List L); //置空链表
int IsEmpty(List L);    //判空链表
int IsLast(Position P,List L);  //判断是否为表尾
Position Find(ElementType X,List L);    //找出元素所在位置
void Delete(ElementType X,List L);      //删除元素
Position FindPrevious(ElementType X,List L);    //找到某元素的前驱
void Insert(ElementType X,List L,Position P);   //插入一个元素
void DeleteList(List L);    //删除链表
Position Header(List L);    //返回头结点
Position First(List L);     //返回第一个元素
Position Advance(Position P);   //返回后一个位置
ElementType Retrieve(Position P);   //获取位置P处的元素值

#endif // _List_H

声明完了以后,我们就要逐步实现这些单链表的ADT,实现的代码放在List.c中

具体实现代码如下:

/**
* @file    List.h
* @brief   链表的实现部分
* @details
* @author   mrbourne@163.com
* @date     2014-5-19
*/
#include <stdio.h>
#include <stdlib.h>
#include <List.h>	//别忘了先把声明部分的头文件List.h包含进来

//实现节点结构体
struct Node
{
    ElementType Element;	//元素
    Position    Next;		//指向下个元素的指针
};

//空链表返回true
int IsEmpty(List L)
{
    return L->Next == NULL;
}

//当前位置是否为链表末尾
int IsLast(Position P, List L)
{
    return P->Next == NULL;
}

//找到一个元素所在的位置
Position Find(ElementType X, List L)
{
    Position P;
    P = L->Next;    //P初始化为a1
    while(P != NULL && P->Element != X)		//只要没到表尾,且当前节点中的元素不等于所给参数,就一直向后遍历
        P = P->Next;
    return P;
}
//找到某个元素的前驱
Position FindPrevious(ElementType X, List L)
{
    Position P;
    while(P->Next != NULL && P->Next->Element != X)	//下一个元素没到表尾,且下一个元素不匹配,则继续遍历
        P = P->Next;
    return P;
}

//删除某个元素x
void Delete(ElementType X, List L)
{
    Position P,TmpCell; //前驱和当前节点
    P = FindPrevious(X,L);
    if(!IsLast(P,L))    //成功找到了该元素的前驱,若IsLast成立,则表示没有找到前驱
    {
        TmpCell = P->Next;	
        P->Next = TmpCell->Next;
        free(TmpCell);
    }
}

//打印错误信息
void FatalError(char *str)
{
    printf("%s\n", str);
}

//在某个元素前插入一个元素
void Insert(ElementType X, List L, Position P)
{
    Position NewCell;
    NewCell = malloc(sizeof(struct Node));  //申请空间
    if(NewCell == NULL)
        FatalError("Out of space!!!");

    NewCell->Element = X;
    NewCell->Next = P->Next;
    P->Next = NewCell;
}

//删除一个链表
void DeleteList(List L)
{
    Position P,Tmp;
    P = L->Next;
    L->Next = NULL; //释放头结点
    while(P != NULL)    //需要用Tmp保存当前节点 因为在free(P)后 不能再对P引用进行P = P->Next
    {
        Tmp = P->Next;
        free(P);
        P = Tmp;
    }

}

至此,我们已经基本实现一个单链表和其基础的操作。这里有几个例程并没有实现,不要着急,这里的单链表还不能供我们使用,有几个历程和后面我们实现栈和队列时大同小异,等学完栈和队列,我们再回来把剩下的几个例程补上,然后也像测试栈和队列一样,在主程序中来测试一下单链表。



转载于:https://www.cnblogs.com/mrbourne/p/9959462.html

<think>好的,我现在需要帮用户找C语言实现线性表逆置的示例代码或课程设计解决方案。首先,我得确定用户指的是顺序表还是链表,因为两者的逆置方法不同。根据用户的引用内容,用户之前可能接触过单链表和顺序存储结构,所以可能需要两种情况的解答。不过用户的问题里提到了线性表,而线性表包括顺序表和链表两种结构,所以可能需要分别说明。 接下来,我得检查用户提供的引用内容。引用[1]提到了顺序表的头文件SequenceList.h,可能涉及顺序存储结构的实现。引用[2]则详细讲解了链表、队列和栈,特别是链表的头插法和尾插法,以及逆序链表的实现方法。所以用户可能希望得到这两种结构的逆置方法。 首先,针对顺序表的逆置。顺序表是数组形式存储的,逆置可以通过交换首尾元素,依次向中间遍历。例如,第一个元素和最后一个交换,第二个和倒数第二个交换,直到中间位置。代码方面,需要用循环控制交换的位置,时间复杂度是O(n)。需要给出一个函数,参数是顺序表结构体或数组指针,以及长度。 然后是链表的逆置。链表逆置通常有三种方法:头插法、迭代法和递归法。头插法需要遍历原链表,将每个节点用头插法插入新链表,这样自然逆置。迭代法则使用三个指针,逐个反转节点的next指向。递归法则通过递归到链表末端,然后逐步反转指针。引用[2]里提到了迭代法和递归法实现逆序链表,可能用户需要这些方法的代码示例。 用户可能需要具体的代码示例,所以需要写出这两种数据结构的逆置函数。同时,课程设计解决方案可能需要包括问题分析、设计思路、代码实现测试案例等部分。但用户可能更关注代码部分,所以先提供代码,再简要说明设计思路。 需要注意代码的规范性和可读性,比如函数参数、变量命名,以及注释。同时,要确保代码符合C语言标准,没有语法错误。例如,顺序表的结构体定义可能包含数据数组和长度,链表节点的结构体包含数据和next指针。 检查引用中的示例代码,比如引用[1]的SequenceList.h可能包含顺序表的定义,而引用[2]中的链表操作可能包含头插法和尾插法。因此,在编写逆置代码时,可以基于这些结构体进行扩展。 另外,用户可能需要考虑逆置操作的时间复杂度和空间复杂度。顺序表的逆置是原地操作,空间复杂度O(1);链表的迭代法也是O(1)空间,递归法可能需要O(n)栈空间。需要指出这些优缺点,帮助用户选择适合的方法。 最后,生成相关问题,比如询问不同方法的区别、如何选择数据结构、逆置的应用场景等,这样可以引导用户进一步学习。</think>### C语言实现线性表逆置的解决方案 线性表逆置操作分为顺序存储结构和链式存储结构两种实现方式,以下是两种结构的详细实现方法: #### 一、顺序表逆置 时间复杂度$O(n)$,空间复杂度$O(1)$ ```c // 顺序表结构定义(参考SequenceList.h[^1]) #define MAXSIZE 100 typedef struct { int data[MAXSIZE]; int length; } SeqList; // 逆置函数 void ReverseSeqList(SeqList *L) { int temp; for(int i=0; i < L->length/2; i++) { temp = L->data[i]; L->data[i] = L->data[L->length-1-i]; L->data[L->length-1-i] = temp; } } ``` #### 二、单链表逆置(迭代法) 时间复杂度$O(n)$,空间复杂度$O(1)$ ```c // 链表节点定义 typedef struct Node { int data; struct Node *next; } Node; // 逆置函数(头插法演变)[^2] Node* ReverseLinkedList(Node *head) { Node *prev = NULL; Node *current = head; Node *next = NULL; while(current != NULL) { next = current->next; // 保存后继节点 current->next = prev; // 反转指针 prev = current; // 前移prev current = next; // 前移current } return prev; // 新头节点 } ``` #### 三、课程设计要素建议 1. **需求分析**:实现线性表逆置功能,支持顺序表和链表两种存储结构 2. **算法设计**: - 顺序表通过对称交换元素 - 链表使用三指针迭代法 3. **复杂度分析**:标明时间/空间复杂度 4. **测试案例**: ```c // 测试顺序表逆置 SeqList L = {{1,2,3,4,5}, 5}; ReverseSeqList(&L); // 结果应为5,4,3,2,1 // 测试链表逆置 Node *head = CreateList({1,2,3,4,5}); // 需实现创建函数 head = ReverseLinkedList(head); // 结果应为5->4->3->2->1 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值