数据结构,一堆数据的存放方式。

今天我们学习数据结构中的 链表

链表的结构:

链表是一种特殊的数组,它的每个元素称为节点,每个节点包括两个部分:

  • 数据域:存放数据,此部分与数组相同
  • 指针域:存放了下一个节点的地址(单向链表)、存放上一个和下一个节点的地址(双向链表)

链表比数组多了指针域,因为链表结构是通过上一个节点的指针域去找下一个数据,比如有一个链表ABCD四个节点,其中A节点是链表的第一个节点,如果我们要访问D节点里边的数据。操作如下:

  1. 先通过A节点的指针域找到B节点
  2. 再通过B节点的指针域找到C节点
  3. 再通过C节点的指针域找到D节点
  4. 获取D节点数据域的数据

对比数组直接通过下标访问如x=Array[3],链表的访问方式相当麻烦,既然这么麻烦,为什么还有链表这种数据结构呢?因为链表插入删除节点方式十分便捷,在数据量大的时候,删除数组的数据需要把删除数据后面的数据都前移一位,而链表只需要改变前一个元素的指针域,插入和删除操作速度快

这么厉害的东西,还是看程序比较直接

单向链表

1、C语言

1.1、程序清单

本程序包含3个文件

它们分别是:

(此处插入图)

linkList.h:

#ifndef _LINKLIST_H
#define _LINKLIST_H typedef int Elem;
typedef unsigned char uint8_t;
struct LkNode
{
Elem m_eData;
struct LkNode *m_iNext;
};
struct LinkList
{
struct LkNode *m_stListHead;
int m_iLength;
int m_iSize;
}; uint8_t LinkListCreate(struct LinkList *list,int size);
uint8_t LinkListDeleteAll(struct LinkList *list);
uint8_t IsLinkListEmpty(struct LinkList *list);
uint8_t IsLinkListFull(struct LinkList *list);
int GetLinkListLength(struct LinkList *list);
int GetLinkListElemIndex(struct LinkList *list,Elem elem);
uint8_t GetListElem(struct LinkList *list,int index,Elem *elem);
//uint8_t GetLinkListPrevious(int index,Elem* elem);
//uint8_t GetLinkListNext(int index,Elem* elem);
uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem);
uint8_t LinkListInsertHead(struct LinkList *list,Elem elem);
uint8_t LinkListInsertTail(struct LinkList *list,Elem elem);
uint8_t LinkListDelete(struct LinkList *list,int index,Elem *getElem);
void LinkListPrintAll(struct LinkList *list); #endif

LinkList.c

#include "LinkList.h"
#include <stdlib.h>
#include <stdio.h> uint8_t LinkListCreate(struct LinkList *list,int size);
uint8_t LinkListDeleteAll(struct LinkList *list);
uint8_t IsLinkListEmpty(struct LinkList *list);
uint8_t IsLinkListFull(struct LinkList *list);
int GetLinkListLength(struct LinkList *list);
int GetLinkListElemIndex(struct LinkList *list,Elem elem);
uint8_t GetListElem(struct LinkList *list,int index,Elem *elem);
//uint8_t GetLinkListPrevious(int index,Elem* elem);
//uint8_t GetLinkListNext(int index,Elem* elem);
uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem);
uint8_t LinkListInsertHead(struct LinkList *list,Elem elem);
uint8_t LinkListInsertTail(struct LinkList *list,Elem elem);
uint8_t LinkListDelete(struct LinkList *list,int index,Elem *getElem);
void LinkListPrintAll(struct LinkList *list); uint8_t LinkListCreate( struct LinkList *list,int size)
{
if(size<=)
{
return ;
} list->m_stListHead = (struct LkNode *)malloc(sizeof(struct LkNode)); //List head haven't datas,and set list length = 0
list->m_stListHead->m_eData=;//head Node haven't data
list->m_stListHead->m_iNext=NULL;
list->m_iLength = ;
list->m_iSize = size;
return ;
} uint8_t LinkListDeleteAll( struct LinkList *list)
{
struct LkNode *deleteNode ;
struct LkNode *nextNode ;
int i;
if(IsLinkListEmpty(list))
{
return ;
} deleteNode = list->m_stListHead->m_iNext;
nextNode = deleteNode->m_iNext; for(i=;i<list->m_iLength ;i++)
{
nextNode = deleteNode->m_iNext;
free(deleteNode);
deleteNode = nextNode;
}
deleteNode = NULL;
nextNode =NULL;
list->m_iLength = ;
return ;
} uint8_t IsLinkListEmpty(struct LinkList *list)
{
if(list->m_iLength == )
{
return ;
}
return ;
}
uint8_t IsLinkListFull(struct LinkList *list)
{
if(list->m_iLength >=list->m_iSize)
{
return ;
}
return ;
} int GetLinkListElemIndex(struct LinkList *list,Elem elem)
{
struct LkNode *tempNode = list->m_stListHead;
int i;
for(i=;i<list->m_iLength ;i++)
{
tempNode = tempNode->m_iNext;
if(tempNode->m_eData == elem)
{
return i;
}
}
return -;
}
uint8_t GetListElem(struct LinkList *list,int index,Elem *elem)
{
struct LkNode *tempNode;
int i;
if(index< ||index >=list->m_iLength )
{
return ;
} tempNode = list->m_stListHead;
for(i=;i<=index;i++)
{
tempNode = tempNode->m_iNext;
}
*elem = tempNode->m_eData;
return ;
}
uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)
{
struct LkNode *preNode = list->m_stListHead;
struct LkNode *newNode;
struct LkNode *nextNode;
int i; if(index< || index>list->m_iLength)
{
return ;
}
if(IsLinkListFull(list))
{
return ;
} newNode = (struct LkNode *)malloc(sizeof(struct LkNode));
if(newNode ==NULL)//heap empty
{
return ;
}
for(i=;i<index;i++)
{
preNode = preNode->m_iNext;
}
nextNode = preNode->m_iNext;
preNode->m_iNext = newNode;
newNode->m_eData = elem;
newNode->m_iNext = nextNode; list->m_iLength++;
return ;
}
uint8_t LinkListInsertHead(struct LinkList *list,Elem elem)
{
return LinkListInsert(list,,elem);
}
uint8_t LinkListInsertTail(struct LinkList *list,Elem elem)
{
return LinkListInsert(list,list->m_iLength ,elem);
} uint8_t LinkListDelete(struct LinkList *list,int index,Elem *elem)
{
struct LkNode *preNode = list->m_stListHead;
struct LkNode *nextNode;
int i;
if(index< || index >= list->m_iLength)
{
return ;
} for(i=;i<index;i++)
{
preNode = preNode->m_iNext;
}
nextNode = preNode->m_iNext ->m_iNext;
*elem = preNode->m_iNext->m_eData;//get delete data
free(preNode->m_iNext); //delete node of index
preNode->m_iNext = nextNode; list->m_iLength--;
return ;
} void LinkListPrintAll(struct LinkList *list)
{
struct LkNode *tempNode = list->m_stListHead;
int i; printf("list:\r\n");
for(i=;i<list->m_iLength;i++)
{
tempNode = tempNode->m_iNext;
printf("%d\r\n",*tempNode);
}
printf("end\r\n");
}

LinkList.c

最后在main.h中测试

#include "LinkList.h"
#include <stdlib.h>
#include <stdio.h> int main(void)
{
int data[]={,,,,,,,,,};
int deletedata;
int GetListElemData;
int i; struct LinkList *list = (struct LinkList *)malloc(sizeof(struct LinkList ));
LinkListCreate(list,); //LinkListInsert check;
printf("LinkListInsert: 1-5:\r\n");
for(i=;i<;i++)
{
if(LinkListInsert(list,i,data[i]))
printf("Insert succeed:%d\r\n",data[i]);
else
printf("Insert fail:%d\r\n",data[i]);
}
LinkListPrintAll(list); //GetLinkListElemIndex check
printf("GetLinkListElemIndex:data[3]:%d\r\n",GetLinkListElemIndex(list,data[])); //GetListElem check
GetListElem(list,,&GetListElemData);
printf("GetListElem list second data:%d\r\n",GetListElemData); //LinkListDelete check
if(LinkListDelete(list,,&deletedata))
printf("LinkListDelete (getData:%d)\r\n",deletedata );
else
printf("LinkListDelete fail\r\n");
LinkListPrintAll(list); //LinkListInsertHead and LinkListInsertTail
printf("LinkListInsertHead:data[7] and LinkListInsertTail:data[8]\r\n");
LinkListInsertHead(list,data[]);
LinkListInsertTail(list,data[]);
LinkListPrintAll(list); //LinkListDeleteAll check
printf("LinkListDeleteAll:\r\n");
LinkListDeleteAll(list);
LinkListPrintAll(list); free(list);
list=NULL; system("pause");
return ;
}

测试结果

(此处补图)

1.2详解:

本部分讲解几个重要额函数,它们分别是:

1、链表创建函数 uint8_t LinkListCreate( struct LinkList *list,int size)

  在这个函数中,首个参数*list是把链表结构体传入,设定链表的头节点(头节点只有指针域没有数据)、使用参数size来规定链表的最大容纳空间、并把链表现在长度置0。

  

uint8_t LinkListCreate( struct LinkList *list,int size)
{
if(size<=)
{
return ;
} list->m_stListHead = (struct LkNode *)malloc(sizeof(struct LkNode)); //List head haven't datas,and set list length = 0
list->m_stListHead->m_eData=;//head Node haven't data
list->m_stListHead->m_iNext=NULL;
list->m_iLength = ;
list->m_iSize = size;
return ;
}

创建链表

2、链表清空函数 uint8_t LinkListDeleteAll( struct LinkList *list)

  参数*list传入链表地址,通过list中的链表长度参数来删除链表,具体方法是:

  1.   创建一个deleteNode指针指向头节点的下一个元素(第0号元素);
  2.   创建nextNode指针指向deleteNode的下一号元素(第1号元素);
  3.   删除掉deleteNode的内容;
  4.   deleteNode指针指向nextNode的内容(第1号元素);
  5.   上边的234步骤循环直到所用内容删除;
uint8_t LinkListDeleteAll( struct LinkList *list)
{
struct LkNode *deleteNode ;
struct LkNode *nextNode ;
int i;
if(IsLinkListEmpty(list))
{
return ;
} deleteNode = list->m_stListHead->m_iNext;
nextNode = deleteNode->m_iNext; for(i=;i<list->m_iLength ;i++)
{
nextNode = deleteNode->m_iNext;
free(deleteNode);
deleteNode = nextNode;
}
deleteNode = NULL;
nextNode =NULL;
list->m_iLength = ;
return ;
}

链表全部元素删除

3、链表插入函数uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)

  参数*list传入链表地址,index传入插入节点的位置(插入在第几号节点),elem传入节点的数据部分

  1.   判断一下传入的参数是否有,有问题则返回0插入失败
  2.   用malloc申请一个newNode(新的节点);
  3.   找到第index-1的节点(存放在preNode);
  4.   找到第index的节点(存放在nextNode);
  5.   把preNode的Next指针指向newNode;
  6.   把newNode的Next指针指向nextNode;(到这里已经完成插入节点,原来的index元素变成了index+1号元素)
  7.   增加list的长度m_iLength;
uint8_t LinkListInsert(struct LinkList *list,int index,Elem elem)
{
struct LkNode *preNode = list->m_stListHead;
struct LkNode *newNode;
struct LkNode *nextNode;
int i; if(index< || index>list->m_iLength)
{
return ;
}
if(IsLinkListFull(list))
{
return ;
} newNode = (struct LkNode *)malloc(sizeof(struct LkNode));
if(newNode ==NULL)//heap empty
{
return ;
}
for(i=;i<index;i++)
{
preNode = preNode->m_iNext;
}
nextNode = preNode->m_iNext;
preNode->m_iNext = newNode;
newNode->m_eData = elem;
newNode->m_iNext = nextNode; list->m_iLength++;
return ;
}

链表插入节点

2、C++语言

在C++中,使用模板的方法实现

本程序包括3个文件组成,他们分别是:

定义节点类:Node.h

这个类定义了每个节点的两个区域:m_tpData数据域 和 m_tpNext指针域:

#include <iostream>

using namespace std;

template <typename T>
class Node
{
public:
Node();
Node(T data);
~Node();
void setData(T data);
T getData();
void setNext(Node<T> *next);
Node* getNext();
void printData();
private:
T *m_tpData;
Node<T> *m_tpNext;
}; template <typename T>
Node<T>::Node()
{
m_tpData = new T;
m_tpNext=NULL;
} template <typename T>
Node<T>::Node(T data)
{
m_tpData = new T(data);
m_tpNext=NULL;
} template <typename T>
Node<T>::~Node()
{
delete m_tpData;
m_tpData=NULL;
} template <typename T>
void Node<T>::setData(T data)
{
*m_tpData = data;
} template <typename T>
T Node<T>::getData()
{
return *m_tpData;
} template <typename T>
void Node<T>::setNext(Node<T> *next)
{
m_tpNext = next;
} template <typename T>
Node<T>* Node<T>::getNext()
{
return m_tpNext;
} template <typename T>
void Node<T>::printData()
{
cout<<*m_tpData<<endl;
}

链表类 LinkList.h

#include <iostream>
#include "Node.h" using namespace std; template <typename T>
class LinkList
{
public:
LinkList();
~LinkList();
bool isListEmpty();
bool clearList();
int getListLength();
int getElemIndex(T &elem);
bool getListElem(int index,T* elem);
//bool getListPrevious(int index,T* elem);
//bool getListNext(int index,T* elem);
bool ListInsert(int index,T &elem);
bool ListDelete(int index,T *elem);
void ListPrint(void);
private:
Node<T> *m_pList;
int m_iLength;
}; template <typename T>
LinkList<T>::LinkList()
{
m_pList = new Node<T>;
m_pList->setData(NULL);
m_pList->setNext(NULL);
m_iLength=;
} template <typename T>
LinkList<T>::~LinkList()
{
Node<T> *nextNode = m_pList;
while(nextNode->getNext()!=NULL) //delete Node while pointerNext == NULL
{
nextNode=m_pList->getNext();
delete m_pList;
m_pList = nextNode;
}
delete m_pList;//delete last Node
m_pList = NULL;
} template <typename T>
bool LinkList<T>::isListEmpty()
{
if(m_iLength==)
return true;
return false;
} template <typename T>
bool LinkList<T>::clearList()
{
if(isListEmpty())
{
cout<<"List empty clear fail"<<endl;
return false;
} //delete All node except first node
Node<T> *nowNode = m_pList->getNext();
Node<T> *nextNode = m_pList->getNext();
while(nextNode->getNext()!=NULL)
{
nextNode=nowNode->getNext();
delete nowNode;
nowNode = nextNode;
}
delete nowNode;//delete last Node m_iLength = ;
m_pList->setNext(NULL);
return true;
} template <typename T>
int LinkList<T>::getListLength()
{
return m_iLength;
}
template <typename T>
int LinkList<T>::getElemIndex(T &elem)
{
Node<T> *tempNode = m_pList;
for(int i=;i<m_iLength;i++)
{
tempNode = tempNode->getNext();
if(elem == tempNode->getData())
{
return i;
}
}
return -;
}
template <typename T>
bool LinkList<T>::getListElem(int index,T* elem)
{
if(index< || index>= m_iLength)
{
return false;
} Node<T> *tempNode = m_pList;
for(int i=;i<=index;i++)
{
tempNode=tempNode->getNext();
} *elem = tempNode->getData();
return true;
} template <typename T>
bool LinkList<T>::ListInsert(int index,T &elem)
{
//index out of range
if(index< || index>m_iLength)
{
return false;
} //
Node<T> *tempPreNode = m_pList;
for(int i=;i<index;i++)
{
tempPreNode = tempPreNode->getNext();
} Node<T> *newnode = new Node<T>; //create a new node
if(newnode == NULL)
{
cout<<"new node create fail"<<endl;
return false;
}
Node<T> *tempNode= tempPreNode->getNext();//save pre node pointer
tempPreNode->setNext(newnode); //set pre node pointer to new node address
newnode->setNext(tempNode);//set new node pointer to pre node pointer
newnode->setData(elem); //set new node new data
m_iLength++;
return true;
} template <typename T>
bool LinkList<T>::ListDelete(int index,T *elem)
{
//index out of range
if(index< || index>=m_iLength)
{
return false;
} //
Node<T> *tempPreNode = m_pList; //pre node
for(int i=;i<index;i++)//find pre node
{
tempPreNode = tempPreNode->getNext();
} Node<T> * tempNode = tempPreNode->getNext();//save delete point pointer
tempPreNode->setNext(tempNode->getNext());//set pre node point to next node
*elem = tempNode->getData();
delete tempNode; m_iLength--;
return true;
} template <typename T>
void LinkList<T>::ListPrint(void)
{
if(isListEmpty())
{
cout<<"List empty"<<endl;
return;
}
Node<T> *tempNode=m_pList->getNext();
while(tempNode->getNext() != NULL)
{
tempNode->printData();
tempNode = tempNode->getNext();
}
tempNode->printData();
cout<<"end"<<endl;
}

单项链表模板定义完了,我们在main.cpp中使用int类型实例化它、并测试它的功能

#include <iostream>
#include <string>
#include "LinkList.h"
using namespace std; int main(void)
{
/*insert data check*/
int data[]={,,,,,,,,,};
LinkList<int> *linklist = new LinkList<int>;
for(int i=;i<;i++)
{
linklist->ListInsert(i,data[i]);
}
linklist->ListPrint(); /*getElemIndex check*/
cout<<"getElemIndex:"<<linklist->getElemIndex(data[])<<endl; /*getListElem check*/
int getdata;
linklist->getListElem(,&getdata);
cout<<"getListElem:"<<getdata<<endl; /*delete data check*/
int deletedata;
linklist->ListDelete (,&deletedata);
cout<<"delete data:"<<deletedata<<endl;
linklist->ListPrint(); /*clearList check*/
linklist->clearList();
linklist->ListPrint(); delete linklist;
linklist = NULL;
system("pause");
return ;
}

运行结果如下:

数据结构-单向链表 C和C++的实现的更多相关文章

  1. Linux C 数据结构 ->单向链表<-(~千金散尽还复来~)

    之前看到一篇单向链表的博文,代码也看着很舒服,于是乎记录下来,留给自己~,循序渐进,慢慢 延伸到真正的内核链表~(敢问路在何方?路在脚下~) 1. 简介 链表是Linux 内核中最简单,最普通的数据结 ...

  2. Linux C 数据结构 ->单向链表

    之前看到一篇单向链表的博文,代码也看着很舒服,于是乎记录下来,留给自己~,循序渐进,慢慢 延伸到真正的内核链表~(敢问路在何方?路在脚下~) 1. 简介 链表是Linux 内核中最简单,最普通的数据结 ...

  3. python数据结构——单向链表

    链表 ( Linked List ) 定义:由许多相同数据类型的数据项按照特定顺序排列而成的线性表. 特点:各个数据在计算机中是随机存放且不连续. 优点:数据的增删改查都很方便,当有新的数据加入的时候 ...

  4. Python3玩转单链表——逆转单向链表pythonic版

    [本文出自天外归云的博客园] 链表是由节点构成的,一个指针代表一个方向,如果一个构成链表的节点都只包含一个指针,那么这个链表就是单向链表. 单向链表中的节点不光有代表方向的指针变量,也有值变量.所以我 ...

  5. C# 单向链表数据结构 (一)

    单向链表数据结构是有节点组成,每个节点包含两部分,第一部分为存储数据,第二部分为指向下一个节点的指针.注意,有两个特色的节点,分别为“头节点”和“尾节点”,头节点本身没有数据,只存储下一个节点的指针, ...

  6. 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路

    01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...

  7. C语言 - 基础数据结构和算法 - 单向链表

    听黑马程序员教程<基础数据结构和算法 (C版本)>,照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友可 ...

  8. 数据结构——Java实现单向链表

    结点类: /** * @author zhengbinMac * 一个OnelinkNode类的对象只表示链表中的一个结点,通过成员变量next的自引用方式实现线性表中各数据元素的逻辑关系. */ p ...

  9. [置顶] ※数据结构※→☆线性表结构(list)☆============单向链表结构(list single)(二)

    单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始:链表是使用指针进行构造的列表:又称为结点列表,因为链表是由一个个结点组装起来的:其中每个结点都有指 ...

随机推荐

  1. 关于Class.forName(className).newInstance()介绍

    Class.forName(xxx.xx.xx) 返回的是一个类 首先你要明白在java里面任何class都要装载在虚拟机上才能运行.这句话就是装载类用的(和new 不一样,要分清楚). 至于什么时候 ...

  2. swift3.0 coreData的使用-日记本demo

    效果 需求分析 基于官方MasterDetail模板,官方写了很多复杂的coredata逻辑,在此基础上快速开发简单的日记本程序. - 主要功能:增.删.改.查 - 界面用默认的界面,将detail页 ...

  3. Android - 基于 Speex 的高度封装语音库,0 耦合使用

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  4. j2ee中的2是什么意思

    J2EE里面的2是什么意思 1998年Java 1.2版本发布,1999年发布Java 1.2的标准版,企业版,微型版三个版本,为了区分这三个版本,分别叫做Java2SE,Java2EE,Java2M ...

  5. 独立ip的优势

    独立ip的建站优势   我想很多人都想知道,那我就在这里给大家简单介绍下独立ip的优势有那些.                    网站设计是需要很多专业知识的结合,整站不是那么容易就可以设计完成的 ...

  6. 安徽省2016“京胜杯”程序设计大赛_K_纸上谈兵

    纸上谈兵 Time Limit: 1000 MS Memory Limit: 65536 KB Total Submissions: 3 Accepted: 1 Description     战国时 ...

  7. 开机出现Oxc000000e故障的解决方法

    Oxc000000e故障 故障表现:开机时不能正常地登录系统,而是直接弹出图2所示的Oxc000000e故障提示. 原因分析:由于安装或卸载某些比较特殊的软件,往往会对Win7的引导程序造成非常严重的 ...

  8. HTML学习笔记2

    5.超链接 3种超链接: 1. 连接到其他页面 2. 锚: (是链接页面)指给超链接起一个名字,作用是连接到本页面或者其他页面的特定位置.使用name属性给超链起名字,本页要加# 3. 连接到邮件: ...

  9. 【社交系统研发日记五】ThinkSNS+如何计算字符显示长度?

    今天我们来聊一下可能很多人都会头疼的东西:显示长度. 需求是这样的,在字符的显示上,两个英文单词才占一个中文或者其他语言的显示长度.如下: 上面排的是两个英文字母,一个汉字,一个Emoji.你会发现, ...

  10. 使用node自动刷房源并发送可入住房源到邮箱

    因为住的地方离公司太远,每天上下班都要坐很久的班车,所以最近想搬到公司旁边的皖水公寓住.去问了一下公寓的客服,客服说房源现在没有了,只能等到别人退房,才能在网站上申请到. 如果纯靠手动F5刷新浏览器, ...