单链表就是线性表的链式存储结构一般使用的是带头节点的链表,如图所示就是带头结点的单链表(我是用的语法是C++的)
带头结点的好处
单链表基本操作
void InitList(LinkNode* &L)//初始化一个链表
void CreateList_Head(LinkList*& L, Elemtype a[], int n)//头插法创建链表
void CreateList_Tail(LinkList*& L, Elemtype a[], int n)//尾插法创建链表
void DestoryList(LinkNode* &L)//销毁一个链表
bool ListEmpty(LinkList* &L)//判断链表是否为空
int ListLength(LinkList* &L)//求出链表的长度
void DispList(LinkList* &L)//输出链表中的所有元素
bool Get_Elem_List(LinkList *&L,int i,Elemtype &e)//求链表中第i个位置的元素
int LocateList(LinkList *&L ,Elemtype e)//找到链表中第一个值为e的元素的位置
bool InsertList(LinkList *&L,int i,Elemtype e)//在第i个位置插入元素e
bool DeleteList(LinkList *& L ,int i)//删除第i个位置的元素
typedef int Elemtype;
typedef struct List {
Elemtype data; //存放元素
List* next; //指向后继结点
}LinkList; //单链表结点类型
创立一个头结点
void InitList(LinkList*& L)
{
L = new LinkList;//创建头结点
L->next = NULL;
}
注:头插法建立的单链表与实际输入的数据的次序是相反的
void CreateList_Head(LinkList*& L, Elemtype a[], int n)
{
LinkList* p;
L = new LinkList;//就是 L = (LinkList *)malloc(sizeof (LinkList));
L->next = NULL;
for (int i = 0; i < n; i++)
{
p = new LinkList;//与malloc作用一致
p->data = a[i];
p->next = L->next;
L->next = p;
}
}
注:尾插法建立的链表与实际输入的数据的次序是一致的
void CreateList_Tail(LinkList*& L, Elemtype a[], int n)
{
LinkList* p, * s;
L = new LinkList;//malloc
L->next = NULL;
s = L;
for (int i = 0; i < n; i++)
{
p = new LinkList;//malloc
p->data = a[i];
s->next = p;
s = p;
}
s->next = NULL;
}
~初始化在上文已经提及就不再赘述了
释放单链表L占用的内存空间——逐一释放全部结点的空间。
void DestoryList(LinkList*& L)
{
LinkList* pre = L, * p = pre->next; // pre 指向 p 的前驱节点
while (p != NULL) //扫描单链表 L
{
delete pre; //释放 pre 结点
pre = p; //pre、p 同步后移一个结点
p = pre->next;
}
delete pre; //循环结束时 p 为 NULL ,pre指向尾结点,释放它
}
//也可以用 free(); 来释放结点的内存
如果链表为空 返回 true 否则返回 false
bool ListEmpty(LinkList*& L)
{
return (L->next == NULL);//头结点指向NULL说明没有元素存在于链表中
}
就是遍历一次链表返回链表的数据结点个数即他的长度
int ListLength(LinkList*& L)
{
int len = 0;
LinkList* p = L->next;
while (p != NULL) //遍历链表
{
len++;
p = p->next;
}
return len;
}
逐一扫描单链表L的每个数据结点,并显示各个结点data域值
void DispList(LinkList*& L)
{
LinkList* p = L->next;
while (p != NULL)
{
cout << p -> data;
p = p->next;
}
puts("");
}
在链表上找到第i个节点,若存在第i个数据节点,则将其data域值返回
bool Get_Elem_List(LinkList*& L, int i, Elemtype& e)
{
int cnt = 0;
LinkList* p = L;
if (i < 0) return false;
while (cnt < i && p != NULL)
{
cnt++;
p = p->next;
}
if (p == NULL) return false;
else
{
e = p->data;
return true;
}
}
在单链表L中从头开始找第一个值域和e相等的结点,若这个结点存在,就返回其逻辑序号,否则返回-1.
int LocateList(LinkList*& L, Elemtype e)
{
int pos = 1; //p指向首结点,pos设置为1
LinkList* p = L -> next;
while (p != NULL && p->data != e )
{
pos++;
p = p->next;
}
if (p == NULL)
return 0;
else
return pos;
}
在单链表L中找到第 i - 1个结点,由p指向它。若存在这样的结点,将值为e的结点(s指向它)插入到p所指向的结点的后面
就是如图的操作 为了防止p的下一个结点的丢失,所以要按如上顺序进行操作
bool InsertList(LinkList*& L, int i, Elemtype e)
{
int cnt = 0;
LinkList* p = L, * s;
if (i <= 0) return false;
while (cnt < i - 1 && p != NULL)
{
cnt++;
p = p->next;
}
if (p == NULL)
return false;
else
{
s = new LinkList; //生成新的结点进行插入操作
s->data = e; //给新结点s赋值
s->next = p->next;
p->next = s;
return true;
}
}
在链表中找到第i-1个结点,由p指向它。若存在就返回其域值并删除结点后返回true,否则返回false
第二种方法是当你不需要知道删除的元素是什么的时候使用
bool DeleteList(LinkList*& L, int i)
{
int j = 0;
Elemtype e;
LinkList* p = L, * q;
if (i <= 0) return false;
while (j < i - 1 && p != NULL)
{
j++;
p = p->next;
}
if (p == NULL) return false;
else
{
q = p->next;
if (q == NULL)
return false;
e = q->data;
p->next = q->next;
delete q;
return true;
}
}
那么所有的操作到此就结束了//因为是C语言上的数据结构所以没有写C++的链表实现方式。
下面是一个 对学生数据类型的单链表实例
Code
#include
#include
#include
#define la_ji_lian_biao ios::sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
using namespace std;
//typedef int Elemtype;
struct Stu {
int id;
string name;
int score;
};
typedef Stu Elemtype;
typedef struct List {
Elemtype data;
List* next;
}LinkList;
//头插法创建链表
void CreateList_Head(LinkList*& L, Elemtype a[], int n)
{
LinkList* p;
L = new LinkList;
L->next = NULL;
for (int i = 0; i < n; i++)
{
p = new LinkList;
p->data = a[i];
p->next = L->next;
L->next = p;
}
}
//尾插法创建链表
void CreateList_Tail(LinkList*& L, Elemtype a[], int n)
{
LinkList* p, * s;
L = new LinkList;
L->next = NULL;
s = L;
for (int i = 0; i < n; i++)
{
p = new LinkList;
p->data = a[i];
s->next = p;
s = p;
}
s->next = NULL;
}
//初始化
void InitList(LinkList*& L)
{
L = new LinkList;
L->next = NULL;
}
//销毁链表
void DestoryList(LinkList*& L)
{
LinkList* pre = L, * p = pre->next;
while (p != NULL)
{
delete pre;
pre = p;
p = pre->next;
}
delete pre;
}
//判断链表是否为空
bool ListEmpty(LinkList*& L)
{
return (L->next == NULL);
}
//求链表的长度
int ListLength(LinkList*& L)
{
int len = 0;
LinkList* p = L->next;
while (p != NULL)
{
len++;
p = p->next;
}
return len;
}
//输出线性表
void DispList(LinkList*& L)
{
LinkList* p = L->next;
cout << '\t' << '\t' << "学号" << '\t' << '\t' << "姓名" << '\t' << '\t' << "分数" << endl;
while (p != NULL)
{
cout << '\t' << '\t' << p->data.id << '\t' << '\t' << p->data.name << '\t' << '\t' << p->data.score << endl;
p = p->next;
}
puts("");
}
//求链表中第i个元素的值
bool Get_Elem_List(LinkList*& L, int i, Elemtype& e)
{
int cnt = 0;
LinkList* p = L;
if (i < 0) return false;
while (cnt < i && p != NULL)
{
cnt++;
p = p->next;
}
if (p == NULL) return false;
else
{
e = p->data;
return true;
}
}
//查找第一个学号为e的元素序号(位置)
int LocateList(LinkList*& L, Elemtype e)
{
int pos = 0;
LinkList* p = L;
while (p != NULL && p->data.id != e.id )
{
pos++;
p = p->next;
}
if (p == NULL)
return 0;
else
return pos + 1;
}
//插入第i个元素
bool InsertList(LinkList*& L, int i, Elemtype e)
{
int cnt = 0;
LinkList* p = L, * s;
if (i <= 0) return false;
while (cnt < i - 1 && p != NULL)
{
cnt++;
p = p->next;
}
if (p == NULL)
return false;
else
{
s = new LinkList;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
}
//删除第i个元素
bool DeleteList(LinkList*& L, int i)
{
int j = 0;
Elemtype e;
LinkList* p = L, * q;
if (i <= 0) return false;
while (j < i - 1 && p != NULL)
{
j++;
p = p->next;
}
if (p == NULL) return false;
else
{
q = p->next;
if (q == NULL)
return false;
e = q->data;
p->next = q->next;
delete q;
return true;
}
}
int main()
{
la_ji_lian_biao;
LinkList* list;
//初始化链表
InitList(list);
//判断是否为空
if (ListEmpty(list)) puts("YES,list is empty!");
else puts("NO,List is not empty!");
puts("显示YES , 初始化成功 ,若输出NO,请重新运行程序");
int n;
Elemtype a[55];
puts("请输入学生的数量 以及每个同学的学号、姓名、成绩");
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i].id >> a[i].name >> a[i].score;
CreateList_Tail(list, a, n);
cout << "链表list的长度为: " << ListLength(list) << endl;
cout << "输出链表" << endl;
DispList(list);
cout << "请输入你要插入的同学的序号、学号、姓名、分数" << endl;
int pos; Elemtype s;
cin >> pos >> s.id >> s.name >> s.score;
InsertList(list, pos, s);
cout << "输出链表" << endl;
DispList(list);
cout << "请输入你要删除的同学的序号: "; int num; cin >> num;
DeleteList(list, num);
cout << "输出链表" << endl;
DispList(list);
cout << "查找第 x 个同学 并输出该同学的信息 " << endl;
int x; Elemtype e;
cin >> x;
Get_Elem_List(list, x, e);
cout << endl;
cout << "该同学的学号为: " << e.id << endl << "该同学的姓名为: " << e.name << endl << "该同学的成绩为: " << e.score << endl;
cout << "输出链表" << endl;
DispList(list);
cout << "删除链表";
DestoryList(list);
//if (ListEmpty(list)) cout << "删除成功" << endl;
/*cout << "输出链表" << endl;
DispList(list);*/
return 0;
}