1. 知识点回顾
顺序表和单链表区别:
顺序表:(1)特点:长度固定且需要分配一段连续的存储空间,存储密度大,可以使用倍增(具体方法就是判断当前元素如果达到最大,重新开辟2*N的空间,如果当前元素为空间的1/4,可以缩小原来空间至1/2,每次操作的同时要复制原来的旧的元素到新的存储空间中)的方法来动态扩容,将顺序表变成"可变长度"。(2)优点:便于随机访问,时间复制度O(1)。(3)缺点:插入和删除需要移动大量的元素,时间复制度O(n)。
单链表:(1)特点:长度不固定,可以任意增删;存储空间不连续,元素之间使用指针相连;存储密度小;(2)优点:插入和删除元素只需要修改指针,不需要移动元素,时间复制度O(1)。(3)缺点:访问元素都需要从链表头开始,时间复制度O(n)。
2. 单链表定义
链表又分为:单链表、循环链表、双向链表。单链表是由很多个结点组成(没有结点的链表就是空链表),每个结点都包含一个数据域和指针域,指针域指向的是紧邻的下一个结点,最后一个结点指针通常为NULL。单链表又分为有头结点和无头结点的单链表,本文主要讨论带头结点的单链表,在此必须清楚三个概念:开始结点、头指针、头结点。
开始结点:就是链表中的第一个结点,该结点没有直接前驱。
头指针:在没有头结点的前提下,头指针是指向开始结点的指针。有了头指针可以唯一确定一个单链表。
头结点:就是在链表开始结点之前再附加一个结点,头结点指针指向的结点数据域为空,有了头结点之后,头指针指向头结点,无论链表是否为空,头指针总是非空。有了头结点之后,对链表开始结点的操作和其他位置的结点操作是一样的。
语法难点:
因为头结点的指针本身就是个结构指针,所以在需要改变头结点的地方,函数的形参应该为指向头指针的指针。
如果这里不使用二级指针,会导致的问题就是我们已经给函数内分配了内存,但是在函数外却访问不到。
3. 单链表基本操作:
(1)void InitLinkedList(LinkedList* L):初始化一个单链表。
(2)void CreateLinkedList_Head(LinkedList* L,int n):头插法创建单链表。
(3)void CreateLinkedList_Tail(LinkedList* L, int n):尾插法创建单链表。
(4)int InsertLinkedList(LinkedList L, int i, DataType e):在第i个位置插入元素e。
(5)int DeleteElement(LinkedList L, int i):删除第i个位置的元素。
(6)void ClearLinkedList(LinkedList L):清理单链表,保留头结点。
(7)void DestroyLinkedList(LinkedList* L):销毁单链表。
(8)bool IsEmpty(LinkedList L):判断单链表是否为空。
(9)int GetLength(LinkedList L):获取单链表长度。
(10)LinkedList GetElement(LinkedList L, int i):查找第i个位置上的元素。
(11)void OutPut(LinkedList L):遍历输出单链表。
3.1 单链表结构体定义
//系统中已有此状态码定义,要防止冲突
#ifndef OVERFLOW
#define OVERFLOW -2 //堆栈上溢
#endif
typedef int DataType;
//单链表结构体
typedef struct LNode
{
DataType data;
struct LNode* next;
}LNode;
typedef LNode* LinkedList; //指向单链表结点的指针
3.2 初始化单链表
//初始化单链表
void InitLinkedList(LinkedList* L) {
(*L) = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
}
3.3 头插法
//头插法
void CreateLinkedList_Head(LinkedList* L,int n) {
int i;
LinkedList p;
DataType tmp;
*L = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
cout << "头插法建立单链表:\n" << endl;
for (int i=1; i<=n; i++)
{
p = (LinkedList)malloc(sizeof(LNode));
cout << "请输入第" << i << "个数:" << endl;
cin >> tmp;
p->data = tmp;
p->next = (*L)->next;
(*L)->next = p;
}
}
3.4 尾插法
//尾插法
void CreateLinkedList_Tail(LinkedList* L, int n) {
int i;
LinkedList p, q;
DataType tmp;
*L = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
q = *L;
cout << "尾插法建立单链表:\n" << endl;
for (int i=1; i<=n; i++)
{
p = (LinkedList)malloc(sizeof(LNode));
cout << "请输入第" << i << "个数:" << endl;
cin >> tmp;
p->data = tmp;
q->next = p;
q = q->next;
}
q->next = NULL;
}
3.5 在第i个位置插入一个元素e
//在位置i插入元素e
int InsertLinkedList(LinkedList L, int i, DataType e) {
int j = 1;
LinkedList pre, p;
LinkedList new_node;//带插入的结点
pre = L;
cout << "在第"<<i<<"个位置插入元素"<< e << endl;
//寻找第i个结点,并令pre指向其前驱
while (pre->next && j < i)
{
pre = pre->next;
j++;
}
if (!pre->next || j > i)
{
return -1;
}
else
{
p = pre->next;
new_node = (LinkedList)malloc(sizeof(LNode));
new_node->data = e;
pre->next = new_node;
new_node->next = p;
return 1;
}
}
4 代码实现
#include <iostream>
using namespace std;
//系统中已有此状态码定义,要防止冲突
#ifndef OVERFLOW
#define OVERFLOW -2 //堆栈上溢
#endif
typedef int DataType;
//单链表结构体
typedef struct LNode
{
DataType data;
struct LNode* next;
}LNode;
typedef LNode* LinkedList; //指向单链表结点的指针
//清理单链表,保留头结点
void ClearLinkedList(LinkedList L) {
LinkedList pre, p;
pre = L->next;
while (pre)
{
p = pre->next;
free(pre);
pre = p;
}
L->next = NULL;
}
//销毁单链表
void DestroyLinkedList(LinkedList* L) {
LinkedList p = *L;
while (p)
{
p = (*L)->next;
free(*L);
(*L) = p;
}
}
//判断单链表是否为空
bool IsEmpty(LinkedList L) {
//链表存在且只有头结点
if (L != NULL && L->next == NULL)
{
return true;
}
else
{
return false;
}
}
//获取单链表长度
int GetLength(LinkedList L) {
LinkedList p;
int lenght = 0;
cout << "单链表长度:" << endl;
if (L)
{
p = L->next;
while (p)
{
lenght++;
p = p->next;
}
}
return lenght;
}
//查找第i个位置结点的数据
LinkedList GetElement(LinkedList L, int i) {
int j = 1;
DataType e;
LinkedList p = L->next;
cout << "返回第" << i << "个位置的元素:" << endl;
while (p && j<i)
{
p = p->next;
j++;
}
if (!p || j>i)
{
return NULL;
}
else
{
return p;
}
}
void OutPut(LinkedList L) {
LinkedList p = L->next;
cout << "链表中的元素:\n" << endl;
while (p)
{
cout << p->data << endl;
p = p->next;
}
}
//初始化单链表
void InitLinkedList(LinkedList* L) {
(*L) = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
}
//头插法
void CreateLinkedList_Head(LinkedList* L,int n) {
int i;
LinkedList p;
DataType tmp;
*L = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
cout << "头插法建立单链表:\n" << endl;
for (int i=1; i<=n; i++)
{
p = (LinkedList)malloc(sizeof(LNode));
cout << "请输入第" << i << "个数:" << endl;
cin >> tmp;
p->data = tmp;
p->next = (*L)->next;
(*L)->next = p;
}
}
//尾插法
void CreateLinkedList_Tail(LinkedList* L, int n) {
int i;
LinkedList p, q;
DataType tmp;
*L = (LinkedList)malloc(sizeof(LNode));
if (!(*L))
{
exit(OVERFLOW);
}
(*L)->next = NULL;
q = *L;
cout << "尾插法建立单链表:\n" << endl;
for (int i=1; i<=n; i++)
{
p = (LinkedList)malloc(sizeof(LNode));
cout << "请输入第" << i << "个数:" << endl;
cin >> tmp;
p->data = tmp;
q->next = p;
q = q->next;
}
q->next = NULL;
}
//在位置i插入元素e
int InsertLinkedList(LinkedList L, int i, DataType e) {
int j = 1;
LinkedList pre, p;
LinkedList new_node;//带插入的结点
pre = L;
cout << "在第"<<i<<"个位置插入元素"<< e << endl;
//寻找第i个结点,并令pre指向其前驱
while (pre->next && j < i)
{
pre = pre->next;
j++;
}
if (!pre->next || j > i)
{
return -1;
}
else
{
p = pre->next;
new_node = (LinkedList)malloc(sizeof(LNode));
new_node->data = e;
pre->next = new_node;
new_node->next = p;
return 1;
}
}
//删除第i个位置的结点
int DeleteElement(LinkedList L, int i) {
int j = 1;
LinkedList pre, p;
pre = L;
cout << "删除第" << i << "个位置的元素" << endl;
//寻找第i个结点,并令pre指向其前驱
while (pre->next && j < i)
{
pre = pre->next;
j++;
}
if (!pre->next || j > i)
{
return -1;
}
p = pre->next;
pre->next = p->next;
free(p);
return 1;
}
int main()
{
LinkedList L;
InitLinkedList(&L);
//CreateLinkedList_Head(&L, 5);
CreateLinkedList_Tail(&L, 5);
OutPut(L);
InsertLinkedList(L, 2, 100);
OutPut(L);
LinkedList e = GetElement(L, 2);
cout << "e=" << e->data << endl;
int len = GetLength(L);
cout << "len=" << len << endl;
/*DeleteElement(L, 1);
OutPut(L);*/
system("pause");
return 0;
}
代码简单测试了下尾插法创建单链表,并在第2个位置插入元素100: