线性表:零个或多个数据元素的有限序列。
属性:第一个元素没有直接前驱元素和最后一个元素没有直接后继元素,其他每个元素有且仅有一个直接前驱和直接后继元素。
基本操作:创建、增删查改。
分为顺序存储和链式存储。下面分别介绍片两种存储结构的优缺点。
优点: 随机存取结构,查改操作的时间复杂度为O(1)。
缺点:增删操作的时间复杂度为O(n),空间分配过小容易溢出,空间分配过大容易浪费资源。
注意:数组存储线性表,线性表的长度小于等于数组的长度。
优点:多次在同一个位置的插入或删除数据,时间复杂度为O(1)。
1、遍历查找第i个结点,时间复杂度为O(n);
2、插入或删除一个结点,时间复杂度为O(1)。
下面讲解链式存储结构单链表的C++实现,完整代码请在这里下载。
//链表存储结构
struct ListNode
{
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
ListNode() = default;
};//包含数据和指针
bool ListTable::ListEmpty(ListNode* head)
{
if (head == NULL)
return true;
else
return false;
}
int ListTable::ListLength(ListNode* head)
{
ListNode* h = head;
int res = 0;
while (h)
{
h = h->next;
res++;
}
return res;
}
在链表中寻找与elem相等的元素,有的话返回元素序号,没有的话返回-1表示失败。
int ListTable::LocateElem(ListNode* head, int elem)
{
ListNode* h = head;
int i=0;
while (h)
{
if (h->val == elem)
return i;
h = h->next;
i++;
}
return -1;
}
bool ListTable::GetElem(ListNode* head, int i, int& elem)
{
int j;
ListNode* p;
p = head;
j = 0;
while (p && j < i)
{
p = p->next;
++j;
}
if (!p || j > i)
return false;
elem = p->val;
return true;
}
bool ListTable::ListInsert(ListNode* &head, int i, int elem)
{
int j;
ListNode* p, *s;
p = head;
j = 0;
if (i == 0)//如果插入第0个元素
{
s = new ListNode(elem);//将要插入的元素
s->next = head;
//std::cout << s->val << std::endl;
head = s;
return true;
}
while (p && j < i-1)//寻找第i-1个节点
{
p = p->next;
++j;
}
if (!p || j > i)
return false;
s = new ListNode(elem);//将要插入的元素
//下面两行代码一定不能反,标准的链表插入语句
s->next = p->next;
p->next = s;
return true;
}
//删除第i个节点,并将删除的元素保存在elem;
bool ListTable::ListDelete(ListNode* &head, int i, int& elem)
{
int j;
ListNode* p, *s;
p = head;
j = 0;
if (i == 0)//如果删除第0个元素
{
elem = head->val;
head = head->next;
return true;
}
while (p && j < i - 1)//寻找第i-1个节点
{
p = p->next;
++j;
}
if (!p->next || j > i)
return false;
s = p->next;
elem = s->val;//保存删除的元素
p->next = s->next;
delete s;//释放内存
return true;
}
void ListTable::CreateListHead(ListNode* &head, int n)
{
ListNode *p;
int i;
srand(time(NULL));
head = new ListNode();
std::cout <<"头插法原始生成的数据:"<< std::endl;
for (i = 0; i < n; i++)
{
p = new ListNode();
p->val = rand() % 100 + 1;
std::cout << p->val <<" ";
p->next = head->next;
head->next = p;
}
std::cout << std::endl;
head = head->next;
}
void ListTable::CreateListTail(ListNode* &head, int n)
{
ListNode *p, *r;//r为尾部节点
int i;
srand(time(NULL));
head = new ListNode();
r = head;//不能改变原始的head数据
std::cout << "尾插法原始生成的数据:" << std::endl;
for (i = 0; i < n; i++)
{
p = new ListNode();
p->val = rand() % 100 + 1;
std::cout << p->val << " ";
r->next = p;
r = r->next;
}
std::cout << std::endl;
head = head->next;
}
bool ListTable::ClearList(ListNode* &head)
{
ListNode *p, *q;
p = head;
q = head;
while (p)
{
q = p->next;//保留下一个节点
delete p;//释放空间
p = q;
}
head = NULL;
return true;
}
void ListTable::printList(ListNode* head)
{
std::cout << "==========现在开始打印链表==========" << std::endl;
ListNode* l = head;
while (l)//l不为空则继续进行循环
{
std::cout << l->val << " ";
l = l->next;//l指向下一个元素
}
if (l == NULL)
std::cout << "这是一个空链表!" << std::endl;
else
std::cout << std::endl;
std::cout << "==========链表打印完毕==========" << std::endl;
}
完整代码请在这里下载。