目录
线性表是数据结构的第一章,而考研和找工作都喜欢考察这方面的内容,因此,我就用C++实现了单链表,以及一些常见的算法题。
本文的具体内容包括:
- 单链表的基本操作
- 反向输出单链表
- 找到两个单链表的第一个公共结点
- 对单链表进行排序
- 将两个有序的链表合在一起,使之仍然有序
单链表的基本操作
不多说,直接上代码(注意基本操作中参数L的不同):
///初始化一个单链表,申请头结点
void InitList(LinkList *L){
*L = new LNode;
if(*L==NULL){
cout<<"new error"<<endl;
return;
}
(*L)->next = NULL;
}
///释放头结点,将其设为null
void DestroyList(LinkList *L){
LinkList t ;
while((*L)!=NULL){
t = (*L)->next;
delete (*L);
(*L) = t;
}
}
///释放除头结点以外的所有空间
void ClearList(LinkList L){
LinkList t,q=L;
L = L->next;
while(L!=NULL){
t = L->next;
delete L;
L = t;
}
q->next = NULL;
}
///获取链表的长度
int Length(LinkList L){
if(L == NULL)
return -1;
int cnt = 0;
L = L->next;
while(L!=NULL){
++cnt;
L=L->next;
}
return cnt;
}
///返回链表L中第1个与e相等的元素的位置
int locateElem(LinkList L,int e){
if(L==NULL)
return -1;
int index = 0;
L = L->next;
while(L!=NULL){
if(L->data==e){
return index;
}
++index;
L = L->next;
}
return -1;
}
///获取链表第i个元素的值
bool getElem(LinkList L,int i,LNode &e){
if(L==NULL or i<0)
return false;
int j = 0;
L = L->next;
while(L!=NULL){
if(j==i){
e.data=L->data;
e.next=L->next;
return true;
}
++j;
L = L->next;
}
return false;
}
///在L中第i个位置插入结点e
bool ListInsert(LinkList L,int i,LNode e){
if(L==NULL)
return false;
LinkList p;
p = L;
L = L->next;
int j = 0;
while(p!=NULL){
if(j==i){
LinkList t;
t = new LNode;
t->data = e.data;
t->next = e.next;
p->next = t;
t->next = L;
return true;
}
p = L;
L = L->next;
++j;
}
return false;
}
///删除第i个元素,并返回该结点
bool ListDelete(LinkList L,int i,LNode &e){
if(L==NULL)
return false;
LinkList p;
int j = 0;
p = L;
L = L->next;
while(L!=NULL){
if(i==j){
e.data = L->data;
e.next = L->next;
p->next = L->next;
delete L;
return true;
}
p = p->next;
L = L->next;
++j;
}
return false;
}
///打印单链表L
void PrintList(LinkList L){
if(L==NULL)
return;
L = L->next;
while(L!=NULL){
cout<<L->data<<' ';
L = L->next;
}
cout<<" end"<<endl;
}
测试代码:
LinkList L;
InitList(&L);
cout<<"the address of the head node is "<<L<<endl;
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
e.data = 123;
ListInsert(L,0,e);
PrintList(L);
cout<<"the length of L is "<<Length(L)<<endl;
cout<<"the location of 132 is "<<locateElem(L,132)<<endl;
if(getElem(L,1,e)){
cout<<"the value of location 1 is "<<e.data<<endl;
}
if(ListDelete(L,1,e))
cout<<"the value of deleted element is "<<e.data<<endl;
else
cout<<"delete failed"<<endl;
ClearList(L);
cout<<L<<endl;
DestroyList(&L);
cout<<L<<endl;
运行结果:
反向输出单链表
///从尾到头反向输出单链表L
///思路:反向输出很容易就想到栈,
///然后递归的本质就是栈,因此可以用
///递归来实现,先一层层递归到链表尾部,
///当指针为NULL时,返回,返回时输出当前节点的值
void PrintListByReverse(LinkList L){
if(L==NULL)
return;
PrintListByReverse(L->next);
cout<<L->data<<' ';
}
测试代码:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
e.data = 123;
ListInsert(L,0,e);
e.data = 88;
ListInsert(L,0,e);
e.data = 14;
ListInsert(L,0,e);
e.data = 26;
ListInsert(L,0,e);
cout<<"the origin linklist is:"<<endl;
PrintList(L);
cout<<"print list in reverse:"<<endl;
PrintListByReverse(L->next);
cout<<"end"<<endl;
运行结果:
求两个单链表的公共结点
///找到两个链表的第一个公共结点
/**< 思路:若两个单链表有公共结点,那么他们的逻辑结构
肯定是Y形而不是X形(因为节点的next域只有一个),因此,
可以先计算两个链表的长度,然后先让较长的先移动d
(他们的长度差)个节点这样他们就会同时到达公共结点,
只需比较两个指针就可以了 */
bool FindCommonNode(LinkList La,LinkList Lb,LNode &e){
if(La==NULL || Lb==NULL)
return false;
int la,lb;///La/Lb 的长度
la = Length(La);
lb = Length(Lb);
int d = la-lb;
int i = 0;
La = La->next;
Lb = Lb->next;
if(d>0){
while(La!=NULL){
if(i==d){
break;
}
++i;
La = La->next;
}
}
else{
d=-d;
while(Lb!=NULL){
if(i==d){
break;
}
++i;
Lb = Lb->next;
}
}
while(La!=NULL && Lb!=NULL){
if(La == Lb){
e.data = La->data;
e.next = La->next;
return true;
}
La = La->next;
Lb = Lb->next;
}
return false;
}
测试代码:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
LinkList myList;
InitList(&myList);
e.data = 83;
ListInsert(myList,0,e);
e.data = 19;
ListInsert(myList,0,e);
e.data = 46;
ListInsert(myList,0,e);
ConcatList(myList,L);
cout<<"list 1 is:"<<endl;
PrintList(myList);
LinkList hisList;
InitList(&hisList);
e.data = 547;
ListInsert(hisList,0,e);
e.data = 78;
ListInsert(hisList,0,e);
ConcatList(hisList,L);
cout<<"list 2 is:"<<endl;
PrintList(hisList);
if(FindCommonNode(myList,hisList,e))
cout<<"the first common node is "<<e.data<<endl;
运行结果:
单链表排序
///对单链表进行排序
/**< 可使用插入排序,每次从后面选择一个结点,
在前面有序的序列选择一个合适的位置插入 */
void SortList(LinkList L){
if(L==NULL)
return;
LinkList q,r,s,x;
r = L;
x = L;
L=L->next;
bool flag;
while(L!=NULL){
///在前面找到合适的位置插入
s = r;
q = r->next;
flag = false;
while(q!=NULL && q!=L){
///找到第一个比当前结点大的结点
if(q->data > L->data){
flag = true;
x->next = L->next;
L->next = q;
s->next = L;
//PrintList(r);
break;
}
s = s->next;
q = q->next;
}
if(flag!= true)
x=x->next;
L=x->next;
}
}
测试代码:
LinkList L;
InitList(&L);
LNode e;
e.data = 124;
e.next = NULL;
ListInsert(L,0,e);
e.data = 132;
ListInsert(L,0,e);
LinkList myList;
InitList(&myList);
e.data = 83;
ListInsert(myList,0,e);
e.data = 19;
ListInsert(myList,0,e);
e.data = 46;
ListInsert(myList,0,e);
ConcatList(myList,L);
cout<<"before sort:"<<endl;
PrintList(myList);
SortList(myList);
cout<<"after sort:"<<endl;
PrintList(myList);
运行结果:
合并有序单链表
///合并有序单链表La、Lb,放到La里面去,并且合并后的链表仍然有序
void MergeList(LinkList La,LinkList Lb){
LinkList pa = La->next,pb = Lb->next,t;
LNode *r;
La->next = NULL; ///La 作为结果链表的指针
t = La;
while(pa != NULL && pb != NULL){
if(pa->data > pb->data){
r = pb->next; ///r 暂存pb的后继结点
///在La插入
pb->next = La->next;
La->next = pb;
///恢复pb为下一个待比较结点
pb = r;
La = La->next;
}
else{
r = pa->next; ///r 暂存pb的后继结点
///在La插入
pa->next = La->next;
La->next = pa;
///恢复pb为下一个待比较结点
pa = r;
La = La->next;
}
//PrintList(t);
}
if(pa!=NULL)
La->next = pa;
if(pb!=NULL)
La->next = pb;
delete Lb;
}
测试代码:
LNode e;
LinkList List1;
InitList(&List1);
e.data = 24;
ListInsert(List1,0,e);
e.data = 68;
ListInsert(List1,0,e);
e.data = 35;
ListInsert(List1,0,e);
e.data = 123;
ListInsert(List1,0,e);
e.data = 77;
ListInsert(List1,0,e);
e.data = 15;
ListInsert(List1,0,e);
SortList(List1);
LinkList List2;
InitList(&List2);
e.data = 23;
ListInsert(List2,0,e);
e.data = 46;
ListInsert(List2,0,e);
e.data = 98;
ListInsert(List2,0,e);
e.data = 143;
ListInsert(List2,0,e);
e.data = 18;
ListInsert(List2,0,e);
e.data = 85;
ListInsert(List2,0,e);
SortList(List2);
cout<<"list 1 is :"<<endl;
PrintList(List1);
cout<<"list 2 is :"<<endl;
PrintList(List2);
MergeList(List1,List2);
cout<<"after merge:"<<endl;
PrintList(List1);
运行结果:
总结
虽然说单链表逻辑比较简单,但是涉及指针操作,很容易出错,我建议在纸上画图来编写代码,这样思路比较清晰。