概念:
链表:线性表的链式储存结构,用一组任意的存储单元存储线性表的数据元素,这组存储单元可以存在内存中未被占用的任意位置。比起顺序表的每个元素只要存储一个位置来说,链式表不仅要存储数据元素信息外,还要存储它的后继元素的存储地址(指针)。
结构定义:
`数据域:存储数据元素信息的域
指针域:存储直接后继位置的域
指针或域:指针中存储的信息
存储映像: 以上两部分信息组成数据元素,称为结点(Node)
n个结点链接成一个链表,即为线性表(a1,a2,a3,…,an)的链式存储结构
单链表:链表中的每个结点只包含一个指针域
对于线性表来说,总得有头有尾,链表也不例外,所以我们把链表中的第一个结点的存储位置叫做头指针,最后一个结点指针为空(NULL)
头结点的数据域是不存储任何信息的
头结点和头指针的异同:
头结点:
头结点是为了操作的统一和方便而设立的,放在第一个元素的结点之前,其数据域一般无意义(但也可以用存放链表的长度)
有了头结点,对在第一元素结点前插入结点和删除第一结点起操作与其它结点的操作就统一了
头结点不一定是链表的必要元素
头指针:
头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针
头指针具有表示作用,所以常用头指针冠以链表的名字(指针变量的名字)
无论链表是否为空,头指针均不为空
头指针是链表的必要元素
单链表是: 头指针->头结点->a1->…->an
空链表是: 头指针->头结点->NULL
单链表结构体
typedef int DataType;
typedef struct ListNode
{
DataType data;//数据域
struct ListNode *next;//指针域
}Node;
typedef struct Node* LinkList;
假设p是指向线性表第i个元素的指针,则该结点ai的数据域可以用p->data的值是一个数据元素,结点ai的指针域可以用p->next来表示,p->next的值是一个指针
即p->next=ai,p->next->data=ai+1
链表实现(C++)
//LinkLst.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
typedef int DataType;
class Node
{
public:
int data;
Node * next;
};
class LinkList
{
public:
LinkList();//初始构造
~LinkList();//销毁
void CreateLinkList(int n);//创建单链表
void TravalLinkList();//遍历单链表
int GetLength();//获取长度
bool IsEmpty();//判空
Node *Find(DataType data);//查找
void InsertElemAtEnd(DataType data);//尾插
void InsertElemAtIndex(DataType data,int n);//在指定位置插入指定元素
void InsertElemAtHead(DataType data);//头插
void DeleteElemAtEnd();//尾删
void DeleteAll();//删除所有数据
void DeleteElemAtPoint(DataType data);//删除指定的数据
void DeleteElemAtHead();//头删节点
private:
Node * head;
};
LinkList::LinkList()
{
head = new Node;
head->data = 0;
head->next = nullptr;
}
LinkList::~LinkList()
{
delete head;
}
void LinkList::CreateLinkList(int n)
{
Node * newp, *tempp;
tempp = head;
if (n<0)
{
cout << "输入有误,请重新输入!" << endl;
false;
}
for (int i=0;i<n;i++)
{
newp = new Node;
cout << "请输入第" << i + 1 << "个值:";
cin >> newp->data;
newp->next = nullptr;
tempp->next = newp;
tempp = newp;
}
}
void LinkList::TravalLinkList()
{
if (head==nullptr)
{
cout << "链表为空!" << endl;
}
Node * p = head;
while (p->next!=nullptr)
{
p = p->next;
cout << p->data << " ";
}
cout << endl;
}
int LinkList::GetLength()
{
int count = 0;
Node * p = head;
while (p->next!=nullptr)
{
count++;
p = p->next;
}
return count;
}
bool LinkList::IsEmpty()
{
if (head->next==nullptr)
{
return false;
}
return true;
}
Node * LinkList::Find(DataType data)
{
Node * p = head;
if (p==nullptr)
{
cout << "此链表为空!" << endl;
return 0;
}
else
{
while (p->next!=nullptr)
{
if (p->data==data)
{
return p;
}
p = p->next;
}
if (p->data==data)
{
return p;
}
return nullptr;
}
}
void LinkList::InsertElemAtEnd(DataType data)
{
Node * newNode = new Node;
newNode->next = nullptr;
newNode->data = data;
Node * p = head;
if (p==nullptr)
{
head = newNode;
}
else
{
while (p->next!=nullptr)
{
p = p->next;
}
p->next = newNode;
}
}
void LinkList::InsertElemAtIndex(DataType data, int n)
{
if (n<1||n>GetLength())
{
cout << "输入有误!" << endl;
}
else
{
Node *tempp = new Node;
tempp->data = data;
Node * p = head;
while (n>1)
{
p = p->next;
n--;
}
tempp->next = p->next;
p->next = tempp;
}
}
void LinkList::InsertElemAtHead(DataType data)
{
Node * newNode = new Node;
newNode->data = data;
Node * p = head;
if (head==nullptr)
{
head = newNode;
}
newNode->next = p->next;
p->next = newNode;
}
void LinkList::DeleteElemAtEnd()
{
Node * p = head;
Node *tempp = nullptr;
if (p->next==nullptr)
{
cout << "链表已为空!" << endl;
}
else
{
while (p->next!=nullptr)
{
tempp = p;
p = p->next;
}
delete p;
p = nullptr;
tempp->next = nullptr;
}
}
void LinkList::DeleteAll()
{
Node * p = head;
Node *tempp = new Node;
while (p!=nullptr)
{
tempp = p;
p = p->next;
head->next = p;
tempp->next = nullptr;
delete tempp;
}
head->next = nullptr;
}
void LinkList::DeleteElemAtPoint(DataType data)
{
Node * tempp = Find(data);
if (tempp==head->next)
{
DeleteElemAtHead();
}
else
{
Node * p = head;
while (p->next!=nullptr)
{
p = p->next;
}
p->next = tempp->next;
tempp = nullptr;
delete tempp;
}
}
void LinkList::DeleteElemAtHead()
{
Node *p = head;
if (p==nullptr||p->next==nullptr)
{
cout << "链表为空!" << endl;
}
else
{
Node * tempp = new Node;
p = p->next;
tempp = p->next;
delete p;
p = nullptr;
head->next = tempp;
}
}
int main()
{
LinkList l;
int i;
cout << "1.创建单链表" << endl << "2.遍历单链表" << endl << "3.获取单链表的长度" << endl << "4.判断单链表是否为空" << endl << "5.获取节点" << endl;
cout << "6.在尾部插入指定元素" << endl << "7.在指定位置插入指定元素" << endl << "8.在头部插入指定元素" << endl << "9.在尾部删除元素" << endl;
cout<< "10.删除所有元素" << endl << "11.删除指定元素" << endl << "12.在头部删除元素" << endl << "0.退出" << endl;
do
{
cout << "请输入要执行的操作: " ;
while (cin >> i)
{
if (i == 1)
{
int n;
cout << "请输入单链表的长度: ";
cin >> n;
l.CreateLinkList(n);
break;
}
if (i == 2)
{
l.TravalLinkList();
break;
}
if (i == 3)
{
cout << "该单链表的长度为" << l.GetLength() << endl;
break;
}
if (i == 4)
{
if (l.IsEmpty() == 1)
cout << "该单链表是空表" << endl;
else
{
cout << "该单链表不是空表" << endl;
}
break;
}
if (i == 5)
{
DataType data;
cout << "请输入要获取节点的值: ";
cin >> data;
cout << "该节点的值为" << l.Find(data)->data << endl;
break;
}
if (i == 6)
{
DataType endData;
cout << "请输入要在尾部插入的值: ";
cin >> endData;
l.InsertElemAtEnd(endData);
break;
}
if (i == 7)
{
DataType pointData;
int index;
cout << "请输入要插入的数据: ";
cin >> pointData;
cout << "请输入要插入数据的位置: ";
cin >> index;
l.InsertElemAtIndex(pointData, index);
break;
}
if (i == 8)
{
DataType headData;
cout << "请输入要在头部插入的值: ";
cin >> headData;
l.InsertElemAtHead(headData);
break;
}
if (i == 9)
{
l.DeleteElemAtEnd();
break;
}
if (i == 10)
{
l.DeleteAll();
break;
}
if (i == 11)
{
DataType pointDeleteData;
cout << "请输入要删除的数据: ";
cin >> pointDeleteData;
l.DeleteElemAtPoint(pointDeleteData);
break;
}
if (i == 12)
{
l.DeleteElemAtHead();
break;
}
else
break;
}
}
while (i != 0);
system("pause");
return 0;
}