一、概念
零个或多个数据元素的有限序列
的是用一段地址连续的存储单元依次存储线性表的数据元
存储器中的每个存储单元都有自己的编号,这个编号称为地址
每个数据元素,不管它是整型,实型还是字符型,它都是需要占用一定的存储单元空间的
线性表的存取操作时间性能为
假设占用的是 c 个存储单元,那么对于线性表的第 i 个数据元素 的存储位置都可以由 推导算出:
二、顺序表的实现 --数组代码
线性表是具有相同数据类型的n(n>0)个数据元素的有限序列,其中n为表长,当n=0时线性表是一个空表
#include "stdafx.h"
#include <iostream>
using namespace std;
#define MaxSize 30
//#define LIST_INIT_SIZE 80//线性表存储空间的初始化分配量
//#define LISTINCREMENT 10//线性表存储空间的分配增量
typedef int Elemtype;
typedef struct Sqlist *List;
struct Sqlist
{
Elemtype data[MaxSize];
int length;
};
//struct Sqlist L;
//List PtrL;
//创建空的顺序表
List MakeEmpty()
{
List PtrL;
PtrL = (List)malloc(sizeof(struct Sqlist));
PtrL->length = -1;
return PtrL;
}
//创建顺序表
void CreateList(List Ptrl)
{
for (int i = 0; i < 10; i++)
{
Ptrl->data[i] = i;
Ptrl->length++;
}
return ;
}
//查找顺序表的元素的位置
int find(Elemtype X, List Ptrl)
{
int i = 0;
while (i <= Ptrl->length&&Ptrl->data[i] != X)
i++;
if (i > Ptrl->length)
return -1;
else
return i;
}
//插入元素
void insert(Elemtype X, int i, List Ptrl)
{
int j;
if (Ptrl->length == MaxSize - 1)
{
printf("表已满,无法插入\n");
return;
}
if (i == 1 || i > Ptrl->length + 2)
{
printf("插入位置不合法,插入失败\n");
return;
}
for (j = Ptrl->length;j>=i; j--)
{
Ptrl->data[j + 1] = Ptrl->data[j];
}
Ptrl->data[i] = X;
Ptrl->length++;
printf("插入成功\n");
return;
}
//删除元素
void deleteEnum( int i, List Ptrl)
{
int j;
if (i < 0 || Ptrl->length < i)
{
printf("数组内不存在此元素位置\n");
return;
}
for (j = i + 1; j <= Ptrl->length; j++)
{
// 从前往后依次向前挪一个,将 a[i] 覆盖了
Ptrl->data[j - 1] = Ptrl->data[j];
}
Ptrl->length--;
}
// 按序查找第K个位置的元素
Elemtype FindKth(int K, List L) {
if (K < 0 || L->length < K) { //位置越界
printf("L->Data[%d]不存在元素\n", K);
return -1;
}
return L->data[K];
}
Elemtype ListLength(List Ptrl)
{
return Ptrl->length;
}
void PrintList(List Ptrl)
{
for (int i = 0; i < Ptrl->length; i++)
{
printf("元素:%d\n", Ptrl->data[i]);
}
}
//主函数
int main()
{
List PtrL= MakeEmpty();
CreateList(PtrL);
PrintList(PtrL);
insert(9, 9, PtrL);
PrintList(PtrL);
FindKth(5, PtrL);
find(3, PtrL);
deleteEnum(5, PtrL);
PrintList(PtrL);
return 0;
}
三、单链表的–链式存储代码
// 线性表-单链表.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
typedef int ElemType;
typedef struct Lnode *List;
//List MakeEmpty(); //初始化链表
//int Length(List L); // 以遍历链表的方法求链表长度
//List FindKth(int K, List L); // 按序号查找
//List Find(ElementType X, List L); // 按值查找
//List Insert(ElementType X, int i, List L); //将 X 插入到第 i-1(i>0) 个结点之后
//List Delete(int i, List L); // 删除第 i(i>0) 个结点
//void Print(List L); // 输出链表元素
struct Lnode
{
ElemType data;
List Next;
};
List L;
//创建一个空链表
List MakeEmpty()
{
List L = (List)malloc(sizeof(struct Lnode));
L = NULL;
return L;
}
//求链表的长度
ElemType Length(List l)
{
ElemType len = 0;
List p = l;
while (p!=NULL)
{
p = p->Next;
len++;
}
return len;
}
//基于位置找元素
List FindKth(int K, List L)
{
List p = L;
int i = 1;
if (p == NULL)
return NULL;
while (p&&i<K)
{
p = p->Next;
i++;
}
if (i == K)
return p;
else
return NULL;
}
//按值查找
List Find(ElemType X, List L)
{
List P = L;
while (P&&P->data!=X)
{
P = P->Next;
}
// 找到了,返回 p
// 未找到,返回 NULL,此时 p 等于 NULL
return P;
}
//插入
//1. 用 s 指向一个新的结点
//2. 用 p 指向链表的第 i - 1 个结点
//3. s->Next = p->Next,将 s 的下一个结点指向 p 的下一个结点
//4. p->Next = s,将 p 的下一结点改为 s * /
List Insert(ElemType X, int i, List L)
{
List P,S;
if (i==1)
{
S=(List)malloc(sizeof(struct Lnode));
S->data = X;
S->Next = L;
return S;
}
P = FindKth(i - 1,L);
if (!P)
{
printf("结点错误");
return NULL;
}
else
{
S = (List)malloc(sizeof(struct Lnode));
S->data = X;
S->Next = P->Next;
P->Next = S;
return L;
}
}
/* 删除
1. 用 p 指向链表的第 i-1 个结点
2. 用 s 指向要被删除的的第 i 个结点
3. p->Next = s->Next,p 指针指向 s 后面
4. free(s),释放空间
*/
List Delete(int i, List L)
{
List P, S;
if (i<1) return NULL;
if (i==1)
{
S = L;
if (L)
{
L = L->Next;
}
else
{
L = NULL;
}
free(S);
return L;
}
P = FindKth(i - 1, L); // 查找第 i-1 个结点
if (!P || !(P->Next)) { // 第 i-1 个或第 i 个结点不存在
printf("结点错误");
return NULL;
}
else {
S = P->Next; // s 指向第 i 个结点
P->Next = S->Next; //从链表删除
free(S); // 释放被删除结点
return L;
}
}
// 输出链表元素
void Print(List L) {
List t;
int flag = 1;
printf("当前链表为:");
for (t = L; t; t = t->Next) {
printf("%d ", t->data);
flag = 0;
}
if (flag)
printf("NULL");
printf("\n");
}
int main()
{
L = MakeEmpty();
Print(L);
L = Insert(11, 1, L);
L = Insert(25, 1, L);
L = Insert(33, 2, L);
L = Insert(77, 3, L);
Print(L);
printf("当前链表长度为:%d\n", Length(L));
printf("此时链表中第二个结点的值是:%d\n", FindKth(2, L)->data);
printf("查找22是否在该链表中:");
if (Find(22, L))
printf("是!\n");
else
printf("否!\n");
printf("查找33是否在该链表中:");
if (Find(33, L))
printf("是!\n");
else
printf("否!\n");
L = Delete(1, L);
L = Delete(3, L);
printf("----------删除后-----\n");
Print(L);
return 0;
}
四、双向链表–代码
// 线性表-双向链表.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
typedef int ElemType;
typedef struct DNode *DLinklist;
struct DNode { //定义双链表结点类型
ElemType data; //数据域
struct DNode *prior, *next; //前驱和后继指针
};
//初始化双链表
bool InitDLinkList(DLinklist &L) {
L = (DNode *)malloc(sizeof(DNode)); //分配一个头结点
if (L == NULL) //内存不足,分配失败
return false;
L->prior = NULL; //头结点的prior指针永远指向NULL
L->next = NULL; //头结点之后暂时还没有结点
return true;
}
void testDLinkList(DLinklist L) {
//初始化双链表
// 定义指向头结点的指针L
InitDLinkList(L); //申请一片空间用于存放头结点,指针L指向这个头结点
//...
}
//find
DNode* FindDP(int position,DLinklist &L) {
DNode* P = L;
int index = 0;
while (P&&index < position)
{
P = P->next;
index++;
}
return P;
}
//判断双链表是否为空
bool Empty(DLinklist L) {
if (L->next == NULL) //判断头结点的next指针是否为空
return true;
else
return false;
}
bool InsertNextDNode(DNode *p, DNode *s) { //将结点 *s 插入到结点 *p之后
if (p == NULL || s == NULL) //非法参数
return false;
s->next = p->next;
if (p->next != NULL) //p不是最后一个结点=p有后继结点
p->next->prior = s;
s->prior = p;
p->next = s;
return true;
}
//删除p结点的后继结点
bool DeletNextDNode(DNode *p) {
if (p == NULL) return false;
DNode *q = p->next; //找到p的后继结点q
if (q == NULL) return false; //p没有后继结点;
p->next = q->next;
if (q->next != NULL) //q结点不是最后一个结点
q->next->prior = p;
free(q);
return true;
}
//销毁一个双链表
bool DestoryList(DLinklist &L) {
//循环释放各个数据结点
while (L->next != NULL) {
DeletNextDNode(L); //删除头结点的后继结点
free(L); //释放头结点
L = NULL; //头指针指向NULL
}
return true;
}
void PrintPrior(DNode *T)
{
DNode *p = T;
while (p != NULL) {
//对结点p做相应处理,eg打印
if (p != NULL)
printf("%d \n ", p->data);
p = p->prior;
}
}
void PrintNext(DNode *T)
{
DNode *p = T;
while (p != NULL) {
//对结点p做相应处理,eg打印
p = p->next;
if (p != NULL)
printf("%d \n ", p->data);
}
}
int main()
{
DLinklist L=NULL;
DNode *node = NULL, *node1 = NULL, *node2 = NULL, *node3 = NULL;
InitDLinkList(node);
InitDLinkList(node1);
InitDLinkList(node2);
InitDLinkList(node3);
InitDLinkList(L);
//testDLinkList(L);
node->data = 1;
InsertNextDNode(L, node);
node1->data = 2;
InsertNextDNode(L, node1);
node2->data =3;
InsertNextDNode(L, node2);
DNode* T= FindDP(1, L);
DeletNextDNode(T);
PrintNext(L);
PrintPrior(L);
return 0;
}
六、循环链表-代码
单链表和循环单链表的比较:
**单链表:**从一个结点出发只能找到该结点后续的各个结点;对链表的操作大多都在头部或者尾部;设立头指针,从头结点找到尾部的时间复杂度=O(n),即对表尾进行操作需要O(n)的时间复杂度;
**循环单链表:**从一个结点出发,可以找到其他任何一个结点;设立尾指针,从尾部找到头部的时间复杂度为O(1),即对表头和表尾进行操作都只需要O(1)的时间复杂度;==优点:==从表中任一节点出发均可找到表中其他结点。