嵌入式 Linux C语言(十二)——单链表

嵌入式 Linux C语言(十二)——单链表

一、单链表简介

1、单链表的结构

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素

链表中的数据是以节点来表示的,每个节点由两部分构成:一个是数据域,存储数据值,另一个是指针域,存储指向下一个节点的指针。

2、单链表的节点

单链表节点的数据结构如下:

typedef struct data

{

unsigned int id;//学生身份ID

char name[LENGTH];//学生姓名

char subject[LENGTH];//科目

unsigned int score;//分数

}DATA,*PDATA;

typedef struct node

{

unsigned int num;//节点序号,头节点则保存链表的节点数量

DATA *data;//数据域

struct node *next;//指针域

}SNode,*PNode;

3、头指针与头结点的区别

头指针与头结点的区别:

二、单链表的操作

1、单链表的创建

头结点的创建:

//初始化单链表,创建头结点

SList slist_init(void)

{

SList head = (Node *)malloc(sizeof(Node));

if(NULL == head)

{

fprintf(stderr, "slist_init function malloc failure.\n");

return NULL;

}

head->next = NULL;

return head;

}

采用尾部插入节点的方式创建单链表:

//根据创建的头结点创建有num个节点的单链表(头结点不算)

int slist_create(SList head, unsigned int num)

{

SList p,r;

r = head;

int i;

for(i = 0; i < num; i++)

{

p = (Node *)malloc(sizeof(Node));//创建新节点

if(NULL == p)

{

fprintf(stderr, "slist_create function p malloc failed.\n");

return ERROR;

}

p->num = i+1;//将各个节点的序号写入节点成员num

p->data.id = 100;

strcpy(p->data.name, "scorpio");

strcpy(p->data.subject, "English");

p->data.score = 100;

r->next = p;

r = p;

}

r->next = NULL;

head->num = slist_size(head);//将创建链表的大小写入头结点num成员

return OK;

}

2、单链表的销毁

//销毁单链表

void slist_destroy(SList list)

{

SList p;

while(list)

{

p = list->next;

free(list);

list = p;

}

}

3、单链表的节点插入操作

void slist_insert(SList list, unsigned int i,PDATA data)

{

if(slist_size(list) < i)

{

fprintf(stdout, "slist_insert function failed.The list size is too samll.There is no element %u.\n", i);

return ;

}

//创建一个节点

SList p = (Node *)malloc(sizeof(Node));

//利用传入的data结构体的数据对节点的数据域进行初始化

p->data.id = data->id;

strcpy(p->data.name, data->name);

strcpy(p->data.subject, data->subject);

p->data.score = data->score;

//找到节点i

SList r = list->next;

if(NULL == r->next)//链表为空时,直接插入

{

//插入节点到链表

p->next = r->next;

r->next = p;

}

else//链表不为空时,先查找插入的位置

{

while(i != r->num)

{

r = r->next;

}

//插入节点到链表

p->next = r->next;

r->next = p;

}

//顺延链表节点i后的节点的序号

int n = i + 1;

r = r->next;

while(r->next)

{

r->num = n++;

r = r->next;

}

r->num = n;//尾节点的序号

list->num = slist_size(list);//将创建链表的大小写入头结点num成员

}

4、单链表的节点删除操作

void slist_delete(SList list, unsigned int i)

{

if(slist_size(list) < i)

{

fprintf(stdout, "slist_insert function failed.The list size is too samll.There is no element %u.\n", i);

return ;

}

SList r = list->next;

if(NULL == r->next)//链表为空时,不能删除

{

fprintf(stderr, "The list is empty.There is no element %u.\n", i);

return ;

}

else//链表不为空时,先查找插入的位置

{

while(i != r->num)

{

r = r->next;

}

//从链表中删除节点

r->next = r->next->next;

}

//顺延链表节点i后的节点的序号

int n = i;

while(r->next)

{

r->num = n++;

r = r->next;

}

r->num = n;//尾节点的序号

list->num = slist_size(list);//将创建链表的大小写入头结点num成员

}

5、获取单链表的长度

//计算单链表的长度,头节点不计算在长度之内

unsigned int  slist_size(SList list)

{

unsigned int count;

SList p = list->next;

while(p)

{

p = p->next;

count++;

}

return count;

}

6、判断单链表是否为空

//判断单链表是否为空

int slist_is_empty(SList list)

{

if(list)

{

fprintf(stdout, "list is no empty.\n");

return 0;

}

else

{

fprintf(stdout, "list is empty.\n");

return 1;

}

}

7、遍历单链表

//遍历单链表

void slist_traverse(SList list)

{

fprintf(stdout, "list size is %u\n", list->num);

SList p = list->next;//跳过头结点

while(p)

{

fprintf(stdout, "id = %u, name = %s, subject = %s, score = %u\n", p->data.id, p->data.name, p->data.subject, p->data.score);

p = p->next;

}

}

8、单链表的翻转(倒序、逆序)

(1)定义当前节点 current,初始值为第一个节点,current =list->next;

(2)定义当前结点的后继节点pnext, pnext = current->next;

(3)将当前第一个节点与后继节点断开,作为尾节点,current->next = NULL;

(4)只要 pnext 存在,表明至少有两个节点,进行逆序,执行以下循环:

A、定义新节点prev,prev是 pnext的后继节点,prev = pnext->next;

B、把pnext的后继指向current, pnext->next = current;

C、此时,pnext 实际上已经到了current 前一位成为新的current,所以这个时候 current 结点实际上成为新的 pnext,current = pnext;

D、此时,新的 current 就是 pnext,current = pnext;

E、而新的 pnext 就是 prev,pnext = prev;

(5)最后将头结点与current重新连上即可,list->next = current;

void slist_reverse(SList list)

{

if(slist_is_empty(list))

{

fprintf(stdout, "The list is empty.No reverse.\n");

return ;

}

SList prev, current, pnext;

current = list->next;//跳过头节点,当前节点为第一个节点

pnext = current->next;//当前节点的下一个节点

current->next = NULL;//当前节点断开后续连接,作为尾节点

while(pnext)

{

prev = pnext->next;//将当前节点的下一个节点作为当前节点的前一个节点

pnext->next = current;//当前节点的前一个节点的指针域指向当前节点

current = pnext;//将下一个节点作为当前节点

pnext = prev;//前一个节点作为下一个节点

}

list->next = current;//头结点指针域指向当前节点,完成逆序

//重新给逆序后的各节点赋值新的序号

int i = 1;

while(current)

{

current->num = i++;

current = current->next;

}

}

参考博文:

小猪的数据结构辅助教程——2.2 线性表中的单链表(CSDN coder-pig

时间: 2024-10-10 20:59:24

嵌入式 Linux C语言(十二)——单链表的相关文章

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

嵌入式Linux C语言(二)——指针

嵌入式Linux C语言(二)--指针 指针是C语言中广泛使用的一种数据类型,是C语言的灵魂.指针提供了动态操控内存的机制,强化了对数据结构的支持,而且实现了访问硬件的功能.学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志. 一.指针的概念 在计算机中,所有的数据都是存放在内存中的,一般把内存中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不一样,如int占用4个字 节,char占用1个字节.为了正确地访问内存单元,必须为每个内存单元编上号.

嵌入式 Linux进程间通信(十二)——多线程同步

嵌入式 Linux进程间通信(十二)--多线程同步 多线程编程中有三种线程同步机制:互斥锁.信号量.条件量.本文将使用生产者消费者问题编程实践三种线程同步方式. 生产者.消费者问题:生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费.消费者线程从缓冲区中获得物品,然后释放缓冲区.当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区.当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来. 一.互斥锁

嵌入式 Linux C语言(十)——静态库函数和动态库函数

嵌入式 Linux C语言(十一)--静态库函数和动态库函数 一.静态链接库 静态链接库是obj文件的一个集合,通常静态链接库以".a"为后缀,名字格式一般为libxxx.a,由程序ar生成.静态链接库是在程序编译过程中链接的,已经将调用的相关函数拷贝到程序内部,程序运行时和静态链接库已经没有任何关系. 1.静态链接库的创建 A.编写源码库文件 源码库文件一般包含.c和.h文件, hello.c文件: #include <stdio.h> void display(void

嵌入式linux C++语言(四)——类与对象

嵌入式linux C++语言(四)--类与对象 类的设计和使用如下: #include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>using namespace std;class Stack{public:    Stack(int size=1024);    ~Stack();    void init();    bool isEmpty();    bool

嵌入式linux C++语言(七)——继承与派生

嵌入式linux C++语言(七)--继承与派生 一.继承 在C++编程中软件可重用性(software reusability)是通过继承(inheritance)机制来实现的.类的继承,是新的类从已有类那里得到已有的特性.或从已有类产生新类的过程就是类的派生.原有的类称为基类或父类,产生的新类称为派生类或子类. 派生类的声明:class 派生类名:[继承方式] 基类名{派生类成员声明:};    一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承. 继承方式规

嵌入式linux C++语言(六)——运算符重载

嵌入式linux C++语言(六)--运算符重载 运算符重载的本质是函数重载. 一.重载基础 1.运算符重载的语法 返值类型 operator 运算符名称(形参表列){    重载实体;} 2.友元重载 可以将运算符重载函数声明位友元函数 #include <iostream> using namespace std; class Complex { public:     Complex(float x=0, float y=0)         :_x(x),_y(y){}     voi

嵌入式 Linux C语言——C语言基础

嵌入式 Linux C语言--C语言基础 一.数据类型 1.基本数据类型 数据类型是创建变量的模型.变量名是连续存储空间的别名,程序中使用变量命名存储空间,通过变量可以使用存储空间.变量所占的内存大小取决于创建变量的数据类型. 2.有符号和无符号 有符号数中数据类型的最高位用于标识数据的符号,最高位为1表示为负数,最高位为0表示为正数. 计算机中有符号数通常使用补码表示,正数的补码为正数本身,负数的补码为负数的绝对值的各位取反后加1. 计算机中无符号数通常使用原码表示,无符号数默认为正数,没有符

嵌入式linux C++语言(一)——C++简介

嵌入式linux C++语言(一)--C++简介 一.C++简介 C语言作是结构化和模块化的语言,适合处理较小规模的程序.对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言并不合适.为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming)思想,支持面向对象的程序设计语言应运而生.Smalltalk 就是当时问世的一种面向对象的语言.在实践工作中,由于C语言的广泛使用,在C语言的基础上根据面向对象的思想发展了C语言,形成了C