单链表
线性表的链式存储又称为链表,它是指的是通过任意一组的存储单元来存储线性表中的数据元素。
单链表的存储
typedef int ElemType;
typedef struct LinkedNode {
ElemType data;//存放数据元素
struct LinkedNode* next;//指向下一个链表结点
}*LinkedList,LinkNode;
Notes
:
- 利用链表可以接解决顺序表需要大量连续存储单元的缺点。
- 由于单链表元素离散地分布在存储空间中,所以单链表是非随机存取地存储结构,查找某个特定结点时,需要从表头开始遍历,依次查找。
- 引入头节点后可以带来两个优点
- 由于第一个数据结点的位置存放在头节点的指针域内,无需进行特殊处理。
- 无论链表是否为空,其头节点都指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也得到了处理
单链表基本操作实现
建立单链表
带头结点的实现
LinkedList List_HeadInsert(LinkedList& L)
{
LinkNode* s;
int x;
InitList(L);//先构造一个空表
scanf_s("%d", &x);//先读入一个x值
while (x != -1)// -1作为读取结束的标志,当然也可以用其他标志
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = L->next;
L->next = s;//这两行代码是插入的关键代码,
//先将L->next赋值给s->next,然后s赋值给L->next;
scanf_s("%d", &x);
}
return L;
}
LinkedList List_TailInsert(LinkedList& L)
{
LinkNode* s;
int x;
InitList(L);
scanf_s("%d", &x);
LinkNode* pt = L;
while (pt->next != NULL)
{
pt = pt->next;//首先找到尾结点,利用边界条件。
}
while (x != -1)
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
pt->next = s;
pt = s;
scanf_s("%d", &x);
}
pt->next = NULL;//这句代码用来指令尾部结点的next是NULL,要不然容易指向野指针!
return L;
}
查找值
LinkNode* GetElem(LinkedList L, int index)
{
if (index < 0 || index > Length(L))
{
std::cout << "index的值不合法!" << std::endl;
return NULL;
}//若index无效,则返回NULL;
if (index == 0)
{
return L;
}
if (L == NULL)
{
return NULL;
}
int j = 1;//计数。初始值为1
LinkNode* pt = L->next;//头结点指针赋值给p
while (pt != NULL && j < index)
// while (pt && j < index)
{
pt = pt->next;
j++;
}
return pt;//返回第i个结点的指针,若i大于表长,则返回NULL
}
按序查找操作的时间复杂度为O(n)
从单链表第一个结点开始,从前往后依次比较表中各节点指针域的值,若某结点数据域的值等于给定值e,则返回该结点的指针;若整个单链表中没有这样的结点,则返回NULL;
LinkNode* LocateElem(LinkedList L, ElemType e) {
LinkNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
时间复杂度为O(n),n为链表的长度
插入结点操作
插入结点操作将值为x的新节点插入到单链表的第i个位置上。先检查插入位置的合法性,然后找到待插入位置的前驱结点,即第i-1个结点,再在其后插入新节点
bool InsertLinkNode(LinkedList L, int index, ElemType e) {
if (index <= 0 || index > Length(L))
{
cout << "index值不合法" << endl;
return false;
}
LinkNode* s;
if (index == 1)//若为第一个位置,直接在表头后面插入即可
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = e;
s->next = L->next;
L->next = s;
return true;
}
s = (LinkNode*)malloc(sizeof(LinkNode));
LinkNode* p = GetElem(L, index - 1);//首先找到第index-1个位置的结点
//执行插入操作
s->next = p->next;
p->next = s;
s->data = e;
return true;
}
本算法主要的时间开销在于查找i-1个元素,时间复杂度为O(N).若在给定的结点后面插入新节点,则时间复杂度为O(1)
删除结点操作
bool ListNodeDelete(LinkedList L, int index) {
if (index <= 0 || index > Length(L))
{
cout << "index值不合法" << endl;
return false;
}
LinkNode* p = GetElem(L, index - 1);
LinkNode* pnext = p->next;
p->next = pnext->next;
free(pnext);
}
时间复杂度为O(n),主要时间开销主要在查找操作上
求表长操作
带头结点求表长
int Length(LinkedList L) {
LinkNode *pt = L->next;
int length = 0;
while (pt != NULL)
{
length++;
pt = pt->next;
}
return length;
}
单链表的原地逆置
LinkedList Reverse_1(LinkedList &L)
{
LinkNode* p = L->next;
LinkNode* q;
L->next = NULL;//首先将原有链表置为空!
while (p != NULL)
{
q = p->next;//q首先指向下一个
p->next = L->next;
L->next = p;//采用头插法插在L后面
p = q;//p再取下一个
}
return L;
}
方法二
LinkedList Reverse_2(LinkedList &L) {
LinkNode* pre, *p = L->next, *r = p->next;
p->next = NULL;
while (r != NULL)
{
pre = p;
p = r;
r = r->next;
p->next = pre;
}
L->next = p;
return L;
}
上述两个算法的时间复杂度为O(N),空间复杂度为O(1)
最后贴出完整代码
#include <iostream>
#include <stdio.h>
using namespace std;
typedef int ElemType;
typedef struct LinkedNode {
ElemType data;
struct LinkedNode* next;
}*LinkedList,LinkNode;
LinkNode* getHead(LinkedList L);
LinkNode* getTail(LinkedList L);
void InitList(LinkedList &L);
int Length(LinkedList L);
LinkedList List_HeadInsert(LinkedList& L);
LinkedList List_TailInsert(LinkedList& L);
void Print(LinkedList L);
LinkNode * GetElem(LinkedList L,int index);
LinkNode* LocateElem(LinkedList L, ElemType e);
bool InsertLinkNode(LinkedList L, int index, ElemType e);
bool ListNodeDelete(LinkedList L, int index);
LinkedList Reverse_1(LinkedList &L);//单链表的原地逆置
LinkedList Reverse_2(LinkedList& L);
void reverseTravese(LinkedList head);
int main()
{
LinkedList L;
List_HeadInsert(L);
Print(L);
/* std::cout << Length(L) << std::endl;
LinkedList LL;
List_TailInsert(LL);
Print(LL);
LinkNode* p = GetElem(L, 5);
cout << p->data << endl;
InsertLinkNode(L, 3, 22);
Print(L);
ListNodeDelete(L, 2);
Print(L);*/
reverseTravese(L);
return 0;
}
void InitList(LinkedList & L) {
L = (LinkNode*)malloc(sizeof(LinkNode));
L->data = 0;
L->next = NULL;
}
int Length(LinkedList L) {
LinkNode *pt = L->next;
int length = 0;
while (pt != NULL)
{
length++;
pt = pt->next;
}
return length;
}
LinkedList List_TailInsert(LinkedList& L)
{
LinkNode* s;
int x;
InitList(L);
scanf_s("%d", &x);
LinkNode* pt = L;
while (pt->next != NULL)
{
pt = pt->next;//首先找到尾结点,利用边界条件。
}
while (x != -1)
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
pt->next = s;
pt = s;
scanf_s("%d", &x);
}
pt->next = NULL;//这句代码用来指令尾部结点的next是NULL,要不然容易指向野指针!
return L;
}
LinkedList List_HeadInsert(LinkedList& L)
{
LinkNode* s;
int x;
InitList(L);//先构造一个空表
scanf_s("%d", &x);//先读入一个x值
while (x != -1)// -1作为读取结束的标志,当然也可以用其他标志
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x;
s->next = L->next;
L->next = s;//这两行代码是插入的关键代码,
//先将L->next赋值给s->next,然后s赋值给L->next;
scanf_s("%d", &x);
}
return L;
}
void Print(LinkedList L)
{
LinkNode* pt = L->next;
while (pt->next != NULL)
{
std::cout << pt->data << " ";
pt = pt->next;
}
std::cout << pt->data << std::endl;
}
LinkNode* GetElem(LinkedList L, int index)
{
if (index < 0 || index > Length(L))
{
std::cout << "index的值不合法!" << std::endl;
return NULL;
}
if (index == 0)
{
return L;
}
if (L == NULL)
{
return NULL;
}
int j = 1;
LinkNode* pt = L->next;
while (pt != NULL && j < index)
// while (pt && j < index)
{
pt = pt->next;
j++;
}
return pt;
}
LinkNode* LocateElem(LinkedList L, ElemType e) {
LinkNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
bool InsertLinkNode(LinkedList L, int index, ElemType e) {
if (index <= 0 || index > Length(L))
{
cout << "index值不合法" << endl;
return false;
}
LinkNode* s;
if (index == 1)
{
s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = e;
s->next = L->next;
L->next = s;
return true;
}
s = (LinkNode*)malloc(sizeof(LinkNode));
LinkNode* p = GetElem(L, index - 1);
s->next = p->next;
p->next = s;
s->data = e;
return true;
}
bool ListNodeDelete(LinkedList L, int index) {
if (index <= 0 || index > Length(L))
{
cout << "index值不合法" << endl;
return false;
}
LinkNode* p = GetElem(L, index - 1);
LinkNode* pnext = p->next;
p->next = pnext->next;
free(pnext);
return true;
}
LinkedList Reverse_1(LinkedList &L)
{
LinkNode* p = L->next;
LinkNode* q;
L->next = NULL;//首先将原有链表置为空!
while (p != NULL)
{
q = p->next;//q首先指向下一个
p->next = L->next;
L->next = p;//采用头插法插在L后面
p = q;//p再取下一个
}
return L;
}
LinkNode* getHead(LinkedList L) {
return L;
}
LinkNode * getTail(LinkedList L)
{
LinkNode* p = L->next;
while (p->next != NULL)
{
p = p->next;
}
return p;
}
LinkedList Reverse_2(LinkedList &L) {
LinkNode* pre, *p = L->next, *r = p->next;
p->next = NULL;
while (r != NULL)
{
pre = p;
p = r;
r = r->next;
p->next = pre;
}
L->next = p;
return L;
}
void reverseTravese(LinkedList head) {
LinkedList p = head->next;
ElemType stack[20];
int top = -1;
while (p != NULL)
{
stack[++top]= p->data;
p = p->next;
}
while (top != 0)
{
cout << stack[top--] << " ";
}
cout << stack[0] << endl;
}