线性表的链式存储结构——链表
线性表的链式存储结构称为链表,其存储结构的特点就是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是非连续的。这样的特点带来的好处就是,只要有未被占用的内存,那么这块内存就可以用来存放数据,需要用的时候就分配,随用随开。可是这样也带来一个问题,我们如何将这一块块存储单元连接起来呢?我们只需要在分配内存存储数据的时候在另外开辟一块指针域,它用来指向下一块(上一块)内存就可以了。
既然同样是用来存储线性表,那总该有头有尾吧,我们把链表的第一个节点称作头结点,一般头结点不用来存放数据(使结点的插入删除操作简便),只用来指向下一个结点。
单链表
在单链表这个数据类型中,应包括存储数据元素的数据域和指向后继结点的指针域。
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LinkNode;
程序代码:
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LinkNode;
void InitList(LinkNode *&L);
void DestroyList(LinkNode *&L);
void ClearList(LinkNode *&L);
void CreateListF(LinkNode *&L, ElemType a[], int n);
void CreateListR(LinkNode *&L, ElemType a[], int n);
bool ListEmpty(LinkNode *L);
int ListLength(LinkNode *L);
void DispList(LinkNode *L);
int LocateElem(LinkNode *L, ElemType e);
bool ListInsert(LinkNode *&L, int i, ElemType e);
void ListAppend(LinkNode *&L, ElemType e);
bool ListDelete(LinkNode *&L, int i, ElemType &e);
void split(LinkNode *&L, LinkNode *&L1, LinkNode *&L2);
void delmaxnode(LinkNode *&L);
void ListSort(LinkNode *&L);
void BubbleSort(LinkNode *&L);
int main(void)
{
/*
int a[9] = {2, 4, 6, 8, 1, 3, 5, 7, 9};
LinkNode *L;
InitList(L);
CreateListR(L, a, 9);
DispList(L);
cout << "表长为:" << ListLength(L) << endl;
ListAppend(L, 80);
DispList(L);
cout << "表长为:" << ListLength(L) << endl;
int e = inf;
ListDelete(L, 0, e);
if (e == inf)
cout << "输入参数有误!" << endl;
else
cout << "所删除的元素为:" << e << endl;
DispList(L);
cout << "表长为:" << ListLength(L) << endl;
DestroyList(L);*/
int a[10] = {3, 2, 4, 1, 3, 8, 5, 1, 7, 9};
LinkNode *L;
InitList(L);
CreateListR(L, a, 10);
DispList(L);
ListSort(L);
DispList(L);
DestroyList(L);
return 0;
}
//初始化线性表 时间复杂度O(1)
void InitList(LinkNode *&L)
{
L = new LinkNode; //为头结点分配内存
L->next = NULL; //将其下一个结点设置为空
}
//销毁线性表(删除头结点) 时间复杂度O(N)
void DestroyList(LinkNode *&L)
{
LinkNode *p = L, *q = p->next;
while (q != NULL)
{
delete p;
p = q;
q = q->next;
}
delete p;
}
//清空线性表(保留头结点) 时间复杂度O(N)
void ClearList(LinkNode *&L)
{
LinkNode *p = L->next;
while (p != NULL)
{
LinkNode *q = p->next;
delete p;
p = q;
if (p != NULL)
q = p->next;
}
L->next = NULL;
}
//头插法建立线性表 时间复杂度O(N)
void CreateListF(LinkNode *&L, ElemType a[], int n)
{
LinkNode *p = L;
for (int i = 0; i < n; i++)
{
LinkNode *q = new LinkNode;
q->data = a[i];
q->next = p->next;
p->next = q;
}
}
//尾插法建立线性表 时间复杂度O(N)
void CreateListR(LinkNode *&L, ElemType a[], int n)
{
LinkNode *p = L;
for (int i = 0; i < n; i++)
{
LinkNode *q = new LinkNode;
q->data = a[i];
p->next = q;
p = q;
}
p->next = NULL;
}
//判断线性表是否为空 时间复杂度O(1)
bool ListEmpty(LinkNode *L)
{
return (L->next == NULL);
}
//求线性表的长度 时间复杂度O(N)
int ListLength(LinkNode *L)
{
LinkNode *p = L;
int k = 0;
while (p->next != NULL)
{
k++;
p = p->next;
}
return k;
}
//按元素查找 时间复杂度O(N)
int LocateElem(LinkNode *L, ElemType e)
{
int i = 1;
LinkNode *p = L->next;
while (p != NULL)
{
if (e == p->data)
break;
i++;
p = p->next;
}
if (p == NULL)
return -1;
else
return i;
}
//插入数据元素 时间复杂度O(N)
bool ListInsert(LinkNode *&L, int i, ElemType e)
{
if (i <= 0)
return false;
LinkNode *p = L->next;
int l = 1;
while (p != NULL)
{
if (l == i-1)
break;
l++;
p = p->next;
}
if (p == NULL)
return false;
else
{
LinkNode *q = new LinkNode;
q->data = e;
q->next = p->next;
p->next = q;
return true;
}
}
//追加数据元素 时间复杂度O(N)
void ListAppend(LinkNode *&L, ElemType e)
{
LinkNode *p = L;
while (p->next != NULL)
p = p->next;
LinkNode *q = new LinkNode;
q->data = e;
q->next = p->next;
p->next = q;
}
//删除数据元素 时间复杂度O(N)
bool ListDelete(LinkNode *&L, int i, ElemType &e)
{
LinkNode *p = L;
int l = 1;
while (p->next != NULL)
{
if (l == i)
break;
l++;
p = p->next;
}
LinkNode *q = p->next;
if (q == NULL)
return false;
else
{
p->next = q->next;
e = q->data;
delete q;
q = NULL;
return true;
}
}
//输出线性表 时间复杂度O(N)
void DispList(LinkNode *L)
{
if (ListEmpty(L))
cout << "链表为空!" << endl;
else
{
LinkNode *p = L->next;
cout << p->data;
p = p->next;
while (p != NULL)
{
cout << "->" << p->data;
p = p->next;
}
cout << endl;
}
}
//例2.6 时间复杂度O(N)
void split(LinkNode *&L, LinkNode *&L1, LinkNode *&L2)
{
LinkNode *p = L->next, *q;
L1 = L;
LinkNode *r = L1;
L2 = new LinkNode;
L2->next = NULL;
while (p != NULL)
{
r->next = p;
r = p;
p = p->next;
q = p->next;
p->next = L2->next;
L2->next = p;
p = q;
}
r->next = NULL;
}
//例2.7 时间复杂度O(N)
void delmaxnode(LinkNode *&L)
{
LinkNode *pre = L, *p = L->next;
LinkNode *maxpre = pre, *maxp = p;
while (p != NULL)
{
if (p->data > maxp->data)
{
maxp = p;
maxpre = pre;
}
pre = p;
p = p->next;
}
maxpre->next = maxp->next;
delete maxp;
maxp = NULL;
}
//例2.8直接插入排序 时间复杂度O(N2)
void ListSort(LinkNode *&L)
{
LinkNode *p, *q, *pre;
p = L->next->next;
L->next->next = NULL;
while (p != NULL)
{
q = p->next;
pre = L;
while (pre->next != NULL)
{
if (p->data < pre->next->data)
break;
pre = pre->next;
}
p->next = pre->next;
pre->next = p;
p = q;
}
}
//冒泡排序 时间复杂度O(N)
void BubbleSort(LinkNode *&L)
{
int len = 0;
LinkNode *p = L->next, *q, *pre;
while (p != NULL)
{
len++;
p = p->next;
}
for (int i = 1; i < len; i++)
{
p = L;
for (int j = 1; j <= len-i; j++)
{
if (p->next->data > p->next->next->data)
{
q = p->next->next;
p->next->next = q->next;
q->next = p->next;
p->next = q;
}
p = p->next;
}
}
}
单链表需要多去模拟一下,需要理清->next的关系,最基本的插入操作一定要熟。
双链表
比起单链表(单链表只能从前往后一个一个遍历),双链表多了一个指向前驱结点的指针,因此在访问一个结点的前后结点更加方便。
typedef struct DNode
{
ElemType data;
struct DNode *prior;
struct DNode *next;
}DLinkNode;
掌握了单链表后,双链表就非常简单了,不过需要在插入的时候考虑插入位置是否为终端,因为要时刻记得不仅有next指针,还有prior指针呀。
程序代码:
#include <iostream>
using namespace std;
typedef int ElemType;
typedef struct DNode
{
ElemType data;
struct DNode *prior;
struct DNode *next;
}DLinkNode;
void InitList(DLinkNode *&L);
void DestroyList(DLinkNode *&L);
void CreateListF(DLinkNode *&L, ElemType a[], int n);
void CreateListR(DLinkNode *&L, ElemType a[], int n);
void DispList(DLinkNode *L);
bool ListInsert(DLinkNode *&L, int i, ElemType e);
bool ListDelete(DLinkNode *&L, int i, ElemType &e);
void ListReverse(DLinkNode *&L);
void ListSort(DLinkNode *&L);
int main(void)
{
int a[6] = {4, 2, 5, 1, 6, 2};
DLinkNode *L;
InitList(L);
CreateListR(L, a, 6);
DispList(L);/*
ElemType e;
ListDelete(L, 6, e);
cout << "所删除元素为:" << e << endl;*/
//ListReverse(L);
ListSort(L);
DispList(L);
DestroyList(L);
return 0;
}
void InitList(DLinkNode *&L)
{
L = new DLinkNode;
L->prior = L->next = NULL;
}
void CreateListF(DLinkNode *&L, ElemType a[], int n)
{
DLinkNode *p;
for (int i = 0; i < n; i++)
{
p = new DLinkNode;
p->data = a[i];
p->next = L->next;
if (L->next != NULL)
L->next->prior = p;
L->next = p;
p->prior = L;
}
}
void CreateListR(DLinkNode *&L, ElemType a[], int n)
{
DLinkNode *p = L, *q;
for (int i = 0; i < n; i++)
{
q = new DLinkNode;
q->data = a[i];
p->next = q;
q->prior = p;
p = q;
}
p->next = NULL;
}
void DispList(DLinkNode *L)
{
if (L->next == NULL)
cout << "链表为空!" << endl;
else
{
DLinkNode *p = L->next;
cout << p->data;
p = p->next;
while (p != NULL)
{
cout << "->" << p->data;
p = p->next;
}
cout << endl;
}
}
void DestroyList(DLinkNode *&L)
{
DLinkNode *p = L, *q = p->next;
while (q != NULL)
{
delete p;
p = q;
q = q->next;
}
delete p;
}
bool ListInsert(DLinkNode *&L, int i, ElemType e)
{
if (i <= 0)
return false;
int j = 0;
DLinkNode *p = L;
while (p != NULL)
{
if (j == i-1)
break;
j++;
p = p->next;
}
if (p == NULL)
return false;
else
{
DLinkNode *q = new DLinkNode;
q->data = e;
q->next = p->next;
if (p->next != NULL) //注意在末尾追加的情况
p->next->prior = q;
q->prior = p;
p->next = q;
return true;
}
}
bool ListDelete(DLinkNode *&L, int i, ElemType &e)
{
if (i <= 0)
return false;
int j = 0;
DLinkNode *p = L;
while (p != NULL)
{
if (j == i-1)
break;
j++;
p = p->next;
}
if (p == NULL)
return false;
else
{
DLinkNode *q = p->next;
if (q == NULL) //注意与插入操作的差别
return false;
e = q->data;
p->next = q->next;
if (p->next != NULL)
p->next->prior = p;
delete q;
q = NULL;
return true;
}
}
void ListReverse(DLinkNode *&L)
{
DLinkNode *p = L->next, *q;
L->next = NULL;
while (p != NULL)
{
q = p->next;
p->next = L->next;
if (p->next != NULL)
p->next->prior = p;
L->next = p;
p->prior = L;
p = q;
}
}
void ListSort(DLinkNode *&L)
{
DLinkNode *p = L->next->next;
L->next->next = NULL;
DLinkNode *pre, *q;
while (p != NULL)
{
q = p->next;
pre = L;
while (pre->next != NULL)
{
if (p->data < pre->next->data)
break;
pre = pre->next;
}
p->next = pre->next;
if (pre->next != NULL)
pre->next->prior = p;
p->prior = pre;
pre->next = p;
p = q;
}
}
掌握链表就一定要多动手多动手!