嵌入式开发学习———Linux环境下数据结构学习(二)
链表的基本概念
链表是一种线性数据结构,由一系列节点组成,每个节点包含数据域和指针域。与数组不同,链表中的元素在内存中不需要连续存储,而是通过指针动态链接。
单向链表的特点
- 每个节点包含数据和一个指向下一个节点的指针(
next
)。 - 只能单向遍历(从头节点到尾节点)。
- 插入和删除操作的时间复杂度为 $O(1)$(已知位置时),但查找需 $O(n)$。
单向链表的简单实现(Python示例)
class Node:def __init__(self, data):self.data = dataself.next = Noneclass LinkedList:def __init__(self):self.head = None
核心操作
插入节点
def insert_at_end(self, data):new_node = Node(data)if not self.head:self.head = new_nodeelse:current = self.headwhile current.next:current = current.nextcurrent.next = new_node
删除节点
def delete_node(self, key):current = self.headif current and current.data == key:self.head = current.nextreturnprev = Nonewhile current and current.data != key:prev = currentcurrent = current.nextif current:prev.next = current.next
优缺点
- 优点:动态大小,高效插入/删除。
- 缺点:随机访问慢,额外内存存储指针。
作业:
单向链表建立等一系列操作 。
#include "linklist.h"int main(int argc, const char *argv[])
{//int i;//int n;//头节点指针linklistptr headptr=NULL;//头节点申请headptr=HeadNodeApply();//定义一个新数据datatype nwedata;for(i=0;i<9;i++){puts("请输入一个数:");scanf(" %d",&nwedata);//调用单向链表的头插函数LinklistHeadinsert(headptr,nwedata);}//调用单向链表的遍历函数LinklistShow(headptr);puts("请输入一个数:");scanf(" %d",&nwedata);//调用单向链表的尾插函数LinklistTailinsert(headptr,nwedata);//调用单向链表的遍历函数LinklistShow(headptr);//调用单向链表的尾删函数puts("尾删后:");LinklistTaildelete(headptr);//调用单向链表的遍历函数LinklistShow(headptr);//调用单向链表的头删函数puts("头删后:");LinklistHeaddelete(headptr);LinklistHeaddelete(headptr);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输入一个数:");scanf(" %d",&nwedata);puts("请输插入的位置:");scanf(" %d",&n);//调用单向链表按位置插入函数LinklistSeatinsert(headptr,n,nwedata);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输删除的位置:");scanf(" %d",&n);//调用单向链表按位置删除函数LinklistSeatdelete(headptr,n);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输入一个数:");scanf(" %d",&nwedata);puts("请输修改的位置:");scanf(" %d",&n);//调用单向链表按位置修改函数LinklistSeatalter(headptr,n,nwedata);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输查找的位置:");scanf(" %d",&n);//调用单向链表按位置查找函数LinklistSeatsift(headptr,n);//调用单向链表的逆置函数Linklistreverse(headptr);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输查找的倒数位置:");scanf(" %d",&n);//调用单向链表按位置查找函数LinklistSeatreversesift(headptr,n);datatype olddata;puts("请输查找的数据:");scanf(" %d",&olddata);//调用单向链表按数据查找函数int seat=LinklistDatasift(headptr,olddata);LinklistSeatsift(headptr,seat);puts("请输入要修改的数据:");scanf(" %d",&olddata);puts("请输入修改后的数据:");scanf(" %d",&nwedata);//调用 单向链表按数据修改函数LinklistDataalter(headptr,olddata,nwedata);//调用单向链表的遍历函数LinklistShow(headptr);puts("请输入要删除的数据:");scanf(" %d",&olddata);//调用单向链表按数据删除函数LinklistDatadelete(headptr,olddata);//调用单向链表的遍历函数LinklistShow(headptr);//单向链表的排序函数LinklistSort(headptr);//调用单向链表的遍历函数LinklistShow(headptr);return 0;
}
#ifndef _LINKLIST_H__
#define _LINKLIST_H__#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>enum returntype
{//失败返回FAULSE=-1,//成功返回SUCCESS
};//存储的数据的数据类型
typedef int datatype;//单向链表的节点结构体
typedef struct Node
{//数据域union {//头节点数据域int len;//普通节点数据域datatype data;}; //指针域struct Node *next;
}linklist,*linklistptr;//头节点申请函数
linklistptr HeadNodeApply(void);//普通节申请函数
linklistptr CommonNodeApply(datatype nwedata);//单向链表的头插函数
int LinklistHeadinsert(linklistptr headptr,datatype nwedata);//单向链表的遍历函数
int LinklistShow(linklistptr headptr);//单向链表的尾插函数
int LinklistTailinsert(linklistptr headptr,datatype nwedata);//单向链表的尾删函数
int LinklistTaildelete(linklistptr headptr);//单向链表的头删函数
int LinklistHeaddelete(linklistptr headptr);//单向链表按位置插入函数
int LinklistSeatinsert(linklistptr headptr,int n,datatype nwedata);//单向链表按位置删除函数(作业)
int LinklistSeatdelete(linklistptr headptr,int n);//单向链表按位置修改函数(作业)
int LinklistSeatalter(linklistptr headptr,int n,datatype nwedata);//单向链表按位置查找函数(作业)
int LinklistSeatsift(linklistptr headptr,int n);//单向链表的逆置函数
int Linklistreverse(linklistptr headptr);//查找链表倒数第n个数据
int LinklistSeatreversesift(linklistptr headptr,int n);//单向链表按数据查找
int LinklistDatasift(linklistptr headptr,datatype olddata);//单向链表按数据修改函数
int LinklistDataalter(linklistptr headptr,datatype olddata,datatype nwedata);//单向链表按数据删除函数
int LinklistDatadelete(linklistptr headptr,datatype olddata);//单向链表的排序函数
int LinklistSort(linklistptr headptr);#endif
#include "linklist.h"//头节点申请函数
linklistptr HeadNodeApply(void)
{//堆区申请linklistptr headptr=(linklistptr)malloc(sizeof(linklist));//判断创建是否成功if(headptr==NULL){return NULL;}//初始化headptr->next=NULL;headptr->len=0;//返回地址return headptr;
}//普通节申请函数
linklistptr CommonNodeApply(datatype nwedata)
{//堆区申请linklistptr comptr=(linklistptr)malloc(sizeof(linklist));//判断创建是否成功if(comptr==NULL){return NULL;}//赋值,初始化comptr->next=NULL;comptr->data=nwedata;//返回地址return comptr;
}//单链表的头插函数
int LinklistHeadinsert(linklistptr headptr,datatype nwedata)
{//判断头指针是否为空if(headptr==NULL){return FAULSE;}//创建一个普通节点并初始化linklistptr comptr=CommonNodeApply(nwedata);//判断普通节点是否为NULLif(comptr==NULL){return FAULSE;}//头插comptr->next=headptr->next;headptr->next=comptr;//链表长度自增headptr->len++;return SUCCESS;
}//单向链表的遍历函数
int LinklistShow(linklistptr headptr)
{//定义一个链表指针linklistptr ptr=NULL;//判断头指针是否为NULL//判断链表是否为空if(headptr==NULL||headptr->len==0){return FAULSE;}//赋值下一个节点地址ptr=headptr->next;//循环输出数据puts("链表现有数据:");while(ptr){printf(" %d",ptr->data);ptr=ptr->next; //}putchar(10);return SUCCESS;
}//单向链表的尾插函数
int LinklistTailinsert(linklistptr headptr,datatype nwedata)
{//定义一个链表指针linklistptr ptr=NULL;//判断头指针是否为空if(headptr==NULL){return FAULSE;}//赋值头结点地址ptr=headptr;//循环找到链表尾部while(ptr->next){ptr=ptr->next;}//创建一个普通节点并初始化linklistptr comptr=CommonNodeApply(nwedata);//判断普通节点是否为空if(comptr==NULL){return FAULSE;}//尾插comptr->next=ptr->next;ptr->next=comptr;//链表长度自增headptr->len++;return SUCCESS;
}//单向链表的尾删函数
int LinklistTaildelete(linklistptr headptr)
{//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空if(headptr==NULL||headptr->len==0){return FAULSE;}//赋值头结点地址ptr=headptr;//循环找到链表次尾部while(ptr->next->next){ptr=ptr->next;}free(ptr->next);ptr->next=NULL;headptr->len--;return SUCCESS;
}//单向链表的头删函数
int LinklistHeaddelete(linklistptr headptr)
{//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空if(headptr==NULL||headptr->len==0){return FAULSE;}//赋值头结点地址ptr=headptr->next;headptr->next=headptr->next->next;//释放删除的空间free(ptr);ptr=NULL;headptr->len--;return SUCCESS;
}//单向链表按位置插入函数
int LinklistSeatinsert(linklistptr headptr,int n,datatype nwedata)
{//定义循环变量int i;//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空//判断n是否合法if(headptr==NULL||headptr->len==0||n<=0||n>headptr->len+1){return FAULSE;}//循环找到链表对应位置ptr=headptr;for(i=0;i<n-1;i++){ptr=ptr->next;}//创建一个普通节点并初始化linklistptr comptr=CommonNodeApply(nwedata);//判断普通节点是否为空if(comptr==NULL){return FAULSE;}//进行插入comptr->next=ptr->next;ptr->next=comptr;headptr->len++;return SUCCESS;
}//单向链表按位置删除函数
int LinklistSeatdelete(linklistptr headptr,int n)
{//定义循环变量int i;//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空//判断n是否合法if(headptr==NULL||headptr->len==0||n<=0||n>headptr->len){return FAULSE;}//循环找到链表对应位置ptr=headptr;for(i=0;i<n-1;i++){ptr=ptr->next;}//进行删除qtr=ptr->next;ptr->next=ptr->next->next;free(qtr);qtr=NULL;headptr->len--;return SUCCESS;
}//单向链表按位置修改函数
int LinklistSeatalter(linklistptr headptr,int n,datatype nwedata)
{//定义循环变量int i;//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空//判断n是否合法if(headptr==NULL||headptr->len==0||n<=0||n>headptr->len){return FAULSE;}//找到对应位置ptr=headptr;for(i=0;i<n;i++){ptr=ptr->next;}//赋值修改ptr->data=nwedata;return SUCCESS;
}//单向链表按位置查找函数
int LinklistSeatsift(linklistptr headptr,int n)
{//定义循环变量int i;//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空//判断n是否合法if(headptr==NULL||headptr->len==0||n<=0||n>headptr->len){return FAULSE;}//找到对应位置ptr=headptr;for(i=0;i<n;i++){ptr=ptr->next;}printf("linklist[%d]=%d\n",n,ptr->data);return SUCCESS;
}//单向链表的逆置函数
int Linklistreverse(linklistptr headptr)
{//定义循环变量int i;//定义两个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空或者只有一个数据if(headptr==NULL||headptr->len<=1){return FAULSE;}//存储头指针指向并断开ptr=headptr->next;headptr->next=NULL;//循环头插for(i=0;i<headptr->len;i++){qtr=ptr;ptr=ptr->next;qtr->next=headptr->next;headptr->next=qtr;}return SUCCESS;
}//查找链表倒数第n个数据
int LinklistSeatreversesift(linklistptr headptr,int n)
{//定义循环变量int i;//定义两个链表指针linklistptr ptr=NULL,qtr=NULL;//判断头指针是否为NULL//判断链表是否为空//判断n是否合法if(headptr==NULL||headptr->len==0||n<=0||n>headptr->len){return FAULSE;}//第一种单循环找倒数ptr=headptr->next;for(i=0;i<headptr->len-n;i++){ptr=ptr->next;}printf("linklist[-%d]=%d\n",n,ptr->data);//第二种双循环找倒数ptr=headptr;qtr=headptr;for(i=0;i<n;i++){qtr=qtr->next;}while(qtr){ptr=ptr->next;qtr=qtr->next;}printf("linklist[-%d]=%d\n",n,ptr->data);return SUCCESS;
}//单向链表按数据查找函数
int LinklistDatasift(linklistptr headptr,datatype olddata)
{//定义循环变量int i;//定义一个链表指针linklistptr ptr=NULL;//判断头指针是否为NULL//判断链表是否为空if(headptr==NULL||headptr->len==0){return FAULSE;}//赋值第一个节点位置并把位置置1ptr=headptr->next;int seat=1;for(i=0;i<headptr->len;i++){if(ptr->data==olddata){//返回位置return seat;}seat++;ptr=ptr->next;}return FAULSE;
}//单向链表按数据修改函数
int LinklistDataalter(linklistptr headptr,datatype olddata,datatype nwedata)
{//定义位置变量int seat;//调用单向链表按数据查找函数并判断seat=LinklistDatasift(headptr,olddata);if(seat==FAULSE){return FAULSE;}//调用单向链表按位置修改函数并判断if(LinklistSeatalter(headptr,seat,nwedata)==FAULSE){return FAULSE;}return SUCCESS;
}//单向链表按数据删除函数
int LinklistDatadelete(linklistptr headptr,datatype olddata)
{//定义位置变量int seat;//调用单向链表按数据查找函数并判断seat=LinklistDatasift(headptr,olddata);if(seat==FAULSE){return FAULSE;}//调用单向链表按位置删除函数并判断if(LinklistSeatdelete(headptr,seat)==FAULSE){return FAULSE;}return SUCCESS;
}//单向链表的排序函数
int LinklistSort(linklistptr headptr)
{int i,j;datatype temp;//定义一个链表指针linklistptr ptr=NULL,qtr=NULL;ptr=headptr->next;for(i=0;i<headptr->len-1;i++){qtr=ptr;for(j=0;j<headptr->len-1;j++){if(qtr->data>qtr->next->data){temp=qtr->data;qtr->data=qtr->next->data;qtr->next->data=temp;}qtr=qtr->next;}}return SUCCESS;
}
运行示例:
2.牛客网刷题