您的位置:首页 > 其它

线性表的链式表示和实现

2018-01-02 10:59 344 查看
前面写了顺序存储结构的线性表,但是由于其插入和删除的时候需要移动大量的元素,所以采用链式的存储可以解决这一点。

由于链式的存储逻辑上的相邻不要求物理位置上的相邻也就是位置相邻  !=  逻辑相邻,因此它就没有顺序存储的移动太多的缺点,同时也就没有了可以随机存储的优点。

链表的存储特点:用一组任意的存储单元存储线性表的数据元素(物理位置可相邻可不相邻)。对应每个数据元素来说除了存储本身的数据元素信息之外(数据域),还需要存储一个指向直接后继的信息(指针域),这两部分的信息构成数据元素的存储映像,称为结点,n个结点链接成链表。整个链表的存取都是从头指针开始进行的,头指针指向链表中的第一个结点的存储位置。同时由于最后一个数据元素没有直接后继,所以它的最后一个结点的指针为NULL。

头结点:我们在单链表的第一个结点之前再加一个结点,称之为头结点,头结点的数据域可以不存储任何数据,也可以存储线性表长度等之类的信息,加入了头结点,保证了所有的元素都有直接前驱。这个时候判空就为头结点的指针域为NULL。



1:不带头结点的线性链表

#include<iostream>

using namespace std;

class LinkList;

class Lnode

{
friend LinkList;

private:
int data;
Lnode *next;

public:
Lnode() { data = 0; next = NULL; };
Lnode(Lnode *ptr) { data = 0; next = ptr; }
Lnode(int value) { data = value; next = NULL; }
Lnode(int value, Lnode *ptr = NULL) { data = value; next = ptr; }/*利用构造函数的重载,做到无头结点的链表,
中间利用不同形式函数对不同的结点进行初始化*/
~Lnode() {}
int getdata() { return data; }
Lnode *getnext() { return next; }//why?为什么是*getnext?
void setnext(Lnode *p) { next = p; }

};

class LinkList

{

private:
Lnode *head;

public:
LinkList() { head = NULL; }
~LinkList() {}
void create1();
void create2();
void emptylist();
int length();
void search(int a);
void insert(int a);
void del(int a);
void show();

};

void LinkList::create1()

{
Lnode *p = new Lnode();
head = NULL;
int n = 0;
cin >> p->data;
while (p->data != -1)
{
n++;
head = p;
p = new Lnode(head);
cin >> p->data;
}
/*
Lnode *p;
head=NUll;
int a;
cin>>a;
while(a!=-1)
{
p=new Lnode(a,head);
head=p;
cin>>a;
}这个和上面的区别就是上面的直接在开始就给p创建了空间,就不用定义a这个变量,还有个区别就是在p重新申请空间的时候直接把后继结点作为参数进行初始化,要求在构造函数那有个对应的类型,并且在没有开空间的时候是不能直接cin>>p->data的,所以个人建议的话还是直接开空间,不然有时候就会涉及到用类里面的函数或者引用变量就会报错。
*/

}

void LinkList::create2()

{
Lnode *p = new Lnode();
Lnode *q = new Lnode();
int n = 0;
cin >> p->data;
while (p->data != -1)
{
n++;
if (n == 1)
{
head = p;
}
else
{
q->setnext(p);
q = p;
p = new Lnode();
cin >> p->data;
}
}

}/*第一个时候直接head=p就可以了,就相当于开始三个结点指向同一个位置,再增加的时候,就由p,q两个个结点向后循化*/

void LinkList::emptylist()

{
Lnode *p = head;
if (p == NULL)
cout << "empty" << endl;
else
cout << "not empty" << endl;

}/*无头结点的链表,判断为空就是head=NULL*/

int LinkList::length()

{
Lnode *p = head;
int n = 0;
if (p == NULL)
cout << n << endl;
else
{
while (p != NULL)
{
n++;
p = p->next;
}
cout << n << endl;
}
return n;

}

void LinkList::search(int a)

{
Lnode *p;
p = head;
int n = 1;
while (p->data != a&&p != NULL)
{
n++;
p = p->next;
}
cout << n << endl;

}

void LinkList::insert(int a)

{
Lnode *p = head;
Lnode *m = new Lnode();
cin >> m->data;
while (p->data != a&&p != NULL)
{
p = p->next;
}
m->setnext(p->next);
p->setnext(m);

}

void LinkList::del(int a)

{
Lnode *p = head;
if (p->data == a)
head = p->next;
else
{
while (p->next->data != a&&p->next != NULL)
{
p = p->next;
}
p->setnext(p->next->next);
}

}/*插入和删除都是一样,要从头指针开始向后检查,我这里的插入的是相同的数,但是要使得有序的话,把判断的条件换一下就行了,也因此,在这里的删除,只删了第一个,因为是之前写的代码就没有改了,这改一下判断条件也就可以了,当改为了有序的时候插入的时候就会覆盖相同的数,也就是链表表中不存在了相同的数,在后面有用链表的排序,到时候再写相关的代码吧。*/

void LinkList::show()

{
Lnode *p;
p = head;
while (p != NULL)
{
cout << p->data << endl;
p = p->next;
}

}

int main()

{
LinkList a;
a.create1();
a.emptylist();
a.length();
a.search(3);
a.del(3);
a.insert(5);
a.show();
LinkList b;
b.create2();
b.show();
return 0;

}


2:带头结点的前插和后插

#include<iostream>

using namespace std;

class LinkList;

class Lnode

{
friend LinkList;

private:
int data;
Lnode *next;

public:
Lnode() { data = 0; next = NULL; };
Lnode(Lnode *ptr) { data = 0; next = ptr; }
Lnode(int value) { data = value; next = NULL; }
Lnode(int value, Lnode *ptr = NULL) { data = value; next = ptr; }/*利用构造函数的重载,做到无头结点的链表,
中间利用不同形式函数对不同的结点进行初始化*/
~Lnode() {}
int getdata() { return data; }
Lnode *getnext() { return next; }//why?为什么是*getnext?
void setnext(Lnode *p) { next = p; }

};

class LinkList

{

private:
Lnode *head;

public:
LinkList() { head = new Lnode(); }
~LinkList() {}
void create1();
void create2();
void emptylist();
int length();
void search(int a);
void insert(int a);
void del(int a);
void show();

};

void LinkList::create1()

{
Lnode *p = new Lnode();
int n = 0;
cin >> p->data;
while (p->data != -1)
{
n++;
head->setnext(p);
p = new Lnode();
p->setnext(head->next);
cin >> p->data;
}

}

void LinkList::create2()

{
Lnode *p = new Lnode();
Lnode *q = new Lnode();
q = head;
cin >> p->data;
while (p->data != -1)
{
q->setnext(p);
q = q->next;
p = new Lnode();
cin >> p->data;
}

}/*

void LinkList::emptylist()

{
Lnode *p = head;
if (p->next == NULL)
cout << "empty" << endl;
else
cout << "not empty" << endl;

}

int LinkList::length()

{
Lnode *p = head;
int n = 0;
if (p->next == NULL)
cout << n << endl;
else
{
while (p->next != NULL)
{
n++;
p = p->next;
}
cout << n << endl;
}
return n;

}

void LinkList::search(int a)

{
Lnode *p;
p = head;
int n = 1;
while (p->next->data != a&&p->next != NULL)
{
n++;
p = p->next;
}
cout << n << endl;

}

void LinkList::insert(int a)

{
Lnode *p = head;
Lnode *m = new Lnode();
cin >> m->data;
while (p->next->data != a&&p->next != NULL)
{
p = p->next;
}
m->setnext(p->next->next);
p->next->setnext(m);

}

void LinkList::del(int a)

{
Lnode *p = head;
if (p->next->data != a&&p->next != NULL)
{
p = p->next;
}
else
{
p->setnext(p->next->next);
}

}

void LinkList::show()

{
Lnode *p;
p = head;
while (p->next != NULL)
{
cout << p->next->data << endl;
p = p->next;
}

}

int main()

{
LinkList a;
a.create1();
a.show();
LinkList b;
b.create2();
b.show();
return 0;

}




3:循环链表和双向链表

循环链表:

双向链表其实基本的操纵与单向链表操作差不多

只是做成了一个环,判断链表是否为空的时候就要换成p->next == head,而不是单向链表的NULL,(还可以不设头指针,而设尾指针!!!!)

void LinkList::create1()

{
Lnode *p = new Lnode();
cin >> p->data;
while (p->data != -1)
{
p->setnext(head->next);
head->setnext(p);
p = new Lnode();
cin >> p->data;
}

}

void LinkList::emptylist()

{
Lnode *p = head;
if (p->next == head)
cout << "empty" << endl;
else
cout << "not empty" << endl;

}

带尾指针的双向链表:

void LinkList::create1()

{
int n = 0;
Lnode *p = new Lnode();
cin >> p->data;
while (p->data != -1)
{
n++;
if (n == 1) {
p->setnext(last);
last->setnext(p);
}
else
{
p->setnext(last->next);
last->setnext(p);
}
p = new Lnode();
cin >> p->data;
}

}

void LinkList::show()

{
Lnode *p = last->next;
while (p != last)
{
cout << p->data << endl;
p = p->next;
}

}




双向链表:

双向链表呢,基本上感觉都差不多的感觉,但是它可以直接找到他的直接前驱和直接后继,直接通过指针访问就可以了,不用像单向链表每次都要从头开始,不同就在在节点类上多了一个类似next的rear指针,在插入和删除的时候不仅要给next赋值还要给rear赋值,其它的基本上没有很明显的区别。

void LinkList::create1()

{
Lnode *p = new Lnode();
cin >> p->data;
while (p->data != -1)
{
p->setnext(head->next);
head->setnext(p);
p->setrear(head);
p = new Lnode();
cin >> p->data;
}

}

void LinkList::insert(int a)

{
Lnode *p = head;
Lnode *m = new Lnode();
cin >> m->data;
while (p->next->data != a&&p->next != NULL)
{
p = p->next;
}
m->setnext(p->next);
p->setnext(m);
m->setrear(p);

}

void LinkList::del(int a)

{
Lnode *p = head;
while (p->next->data != a&&p->next != NULL)
{
p = p->next;
}
p->setnext(p->next->next);
p->next->setrear(p);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线性表