typedef int ElemType;
typedef struct Node
{
ElemType data;
struct Node *next;
}LinkList, *PLinkList;
// type == 1 带头节点
// 计算链表的长度
int length(PLinkList &la, int type)
{
int res = 0;
PLinkList tmp = la;
while (tmp){
res++;
tmp = tmp->next;
}
return type ? res - 1 : res;
}
// type == 0, 不带头节点, type == 1 带头节点
// 顺次打印链表
void printLinkList(PLinkList list, int type)
{
if (list == NULL) return;
PLinkList tmp = list;
if (type == 1) tmp = list->next;
while (tmp)
{
cout << tmp->data << " ";
tmp = tmp->next;
}
cout << endl;
return;
}
// type == 0, 不带头节点, type == 1 带头节点
// 创建一个链表
void createLinkList(PLinkList &list, int type, int len)
{
PLinkList tmp = list;
// 如果先前传进来的list列表不是空表就释放掉
while (list){
list = list->next;
free(tmp);
tmp = list;
}
// 建表
list = new LinkList();
list->next = NULL;
tmp = list;
for (int i = 0; i < len; i++)
{
tmp->next = new LinkList();
tmp->next->next = NULL;
tmp->next->data = rand() % 10;
tmp = tmp->next;
}
if (type == 0)
{
tmp = list;
list = list->next;
free(tmp);
}
return;
}
删除不带头节点的链表中所有值为x的元素,递归实现。
// P1 删除所有值为x的结点 不带头节点,递归实现
void delete_x_nohead(PLinkList &list, ElemType x)
{
if (list == NULL)
return;
if (list->data == x)
{
PLinkList tmp = list;
list = list->next;
free(tmp);
}
delete_x_nohead(list->next, x);
}
删除带头节点的链表中所有值为x的元素。
// P2 删除所有值为x的节点 带头节点
void delete_x_head(PLinkList &list, ElemType x)
{
PLinkList tmp = list;
PLinkList del = NULL;
while (tmp->next)
{
if (tmp->next->data == x)
{
del = tmp->next;
tmp->next = del->next;
free(del);
}
else
tmp = tmp->next;
}
return;
}
反向输出带头节点的链表。
很简单的一种递归,和栈的原理一样,需要注意的是,如果是带头节点的链表传参时,应该略过头节点,比如反向输出带头节点的链表list时,应该传入reversePrintLinkList(list->next)。
// P3 L带头节点,反向输出链表
void reversePrintLinkList(PLinkList list)
{
if (list == NULL) return;
reversePrintLinkList(list->next);
cout << list->data << " ";
return;
}
带头节点的链表中删除最小值的元素。
// p4 带头节点删除最小值元素
void delete_min(PLinkList &list)
{
PLinkList minp = list;
PLinkList tmp = list;
while (tmp->next)
{
if (tmp->next->data < minp->next->data)
{
minp = tmp;
}
tmp = tmp->next;
}
PLinkList delp = minp->next;
minp->next = delp->next;
free(delp);
return;
}
将带头节点的单链表倒置,不允许使用额外空间。
// p5 倒置带头节点的链表, 不允许使用额外空间
void reverseLinkList(PLinkList &list)
{
PLinkList cur = list->next, tail = NULL;
while (cur)
{
PLinkList p = cur->next;
cur->next = tail;
tail = cur;
cur = p;
}
list->next = tail;
return;
}
将带头节点的单链表按升序排序。
课本上给出的做法时使用插入排序,那样做的时间复杂度时O(n*n),下面这种做法是课本中提到的第二种以空间换时间的一种做法,先放到数组里再利用快排进行排序,最后再放回单链表,这样做的时间复杂度是O(n * lg(n))。
// p6 头节点的单链表,使其递增有序, 书上的第二种方法 空间换时间 时间复杂度 O(n*lg(n))
void sort_headLinkList(PLinkList &list)
{
vector<ElemType> vec;
PLinkList tmp = list;
while (tmp->next)
{
vec.push_back(tmp->data);
tmp = tmp->next;
}
sort(vec.begin(), vec.end());
tmp = list->next;
for (int i = 0; i < vec.size(); i++, tmp = tmp->next) tmp->data = vec[i];
return;
}
删除带头节点的单链表中,节点的值介于A和B之间的所有节点。
// p7 删除带头节点的链表中的介于A和B之间的值
void deleteValueInA_B(PLinkList &list, ElemType A, ElemType B)
{
PLinkList tmp = list;
while (tmp->next)
{
if (tmp->next->data <= B && tmp->next->data >= A)
{
PLinkList del = tmp->next;
tmp->next = del->next;
free(del);
}
else
tmp = tmp->next;
}
return;
}
找出两个带头节点的单链表中的公共节点,并以表的形式返回。
// p8 找出带头节点两个单链表中的公共节点,并以表lc返回
void findSameNode(PLinkList la, PLinkList lb, PLinkList &lc)
{
lc = new LinkList(); // 清空表lc, 创建一个头节点
lc->next = NULL;
int lena = length(la, 1), lenb = length(lb, 1);
if (lena < lenb){
swap(la, lb);
swap(lena, lenb);
}
PLinkList ta = la->next, tb = lb->next;
for (int i = 0; i < lena - lenb; i++, ta = ta->next);
while (ta && ta != tb){
ta = ta->next;
tb = tb->next;
}
lc = ta;
return;
}
升序输出带头节点的单链表,并释放节点。
// p9 升序输出带头节点的单链表。并释放节点
void printfIncrease(PLinkList la){
PLinkList il = NULL, jl = NULL;
PLinkList minl = la;
while (la->next){
minl = la;
il = la;
while (il->next){
if (minl->next->data > il->next->data){
minl = il;
}
il = il->next;
}
cout << minl->next->data << " ";
jl = minl->next;
minl->next = jl->next;
free(jl);
}
return;
}
将带头节点的链表A按照序号为奇数还是偶数,分成两个带头节点的单链表。
// p10 将带头节点的链表按照奇序号和偶序号分为两个带头节点的链表
void assortWithID1(PLinkList list, PLinkList &la, PLinkList &lb)
{
la = new LinkList(); la->next = NULL;
lb = new LinkList(); lb->next = NULL; //清空两个将要返回值的链表
int cnt = 1; // 节点序号计数器
PLinkList tmp = list->next;
PLinkList ta = la, tb = lb; // 记录奇偶链表的尾节点
// 注意这种方式没有产生新的节点,是将list中的节点分到了la,lb中
// 那么,这种方式当while循环结束后,已经改变了list链表
while (tmp)
{
if (cnt & 1){ // 为奇数保存到链表la
ta->next = tmp;
ta = tmp;
}
else{ // 为偶数保存到链表lb
tb->next = tmp;
tb = tmp;
}
tmp = tmp->next;
cnt++;
}
ta->next = NULL;
tb->next = NULL;
}
将偶数个元素的、带头节点的链表list,按照奇数、偶数拆分成两个链表, la采用头插法,lb采用尾插法。
// p11 将偶数个元素的、带头节点的链表list,按照奇数、偶数拆分成两个链表,
// la采用头插法,lb采用尾插法
void assortWithID2(PLinkList list, PLinkList &la, PLinkList &lb)
{
la = new LinkList();
lb = new LinkList(); // 清空将要返回结果的两个单链表
la->next = lb->next = NULL;
PLinkList tmp = list->next;
PLinkList ta = la; // la是尾插法,所以要记录尾巴的位置
// 因为题目中说了一定是偶数个元素,所以一次循环可以更改两个元素
while (tmp)
{
ta->next = new LinkList(); // 刚才的p10 说了,那样的做法会改变list 下面这种则不会
ta->next->data = tmp->data; // copy
ta->next->next = NULL;
ta = ta->next;
tmp = tmp->next;
PLinkList t = new LinkList();
t->next = lb->next;
t->data = tmp->data;
lb->next = t; // 头插法, 最好画图模拟,好理解
tmp = tmp->next;
}
return;
}
带头节点、有序的单链表中,去掉重复元素。
// p12 带头节点、有序的单链表中,去掉重复元素
void deWeightLinkList(PLinkList &list)
{
if (!list->next) return; // 保证链表中至少含有一个元素,否则循环会报错
PLinkList tmp = list->next;
while (tmp->next)
{
if (tmp->data == tmp->next->data)
{
PLinkList dl = tmp->next;
tmp->next = dl->next;
free(dl);
}
else
tmp = tmp->next;
}
return;
}
将两个带头节点的有序的单链表,合并成一个递减的链表,要求不能产生新节点,要用原来链表中的节点。
// p13 将两个带头节点的有序的单链表,合并成一个递减的链表
// 要求不能产生新节点,要用原来链表中的节点
void mergeToDecline(PLinkList la, PLinkList lb, PLinkList &lc)
{
lc = new LinkList(); lc->next = NULL; // 清空链表
PLinkList ta = la->next, tb = lb->next;
PLinkList p1 = NULL, p2 = NULL; // 辅助临时节点
while (la || lb){
if (la && lb){
if (la->data > lb->data) p1 = lb, lb = lb->next;
else p1 = la, la = la->next;
}
else if (la) p1 = la, la = la->next;
else p1 = lb, lb = lb->next;
p1->next = lc->next;
lc->next = p1;
}
return;
}
要求从la和lb的公共节点中产生表lc,不能破坏表la,lb的节点,其中要求la,lb,lc均为带头节点的单链表。
// p14 要求从la和lb的公共节点中产生表lc,不能破坏表la,lb的节点
// 都是带头节点的
void getPublicNodeFromAB(PLinkList la, PLinkList lb, PLinkList &lc)
{
lc = new LinkList(); lc->next = NULL; // 清空表lc
PLinkList ta = la->next, tb = lb->next, tc = lc;
while (ta && tb)
{
if (ta->data == tb->data){
tc->next = new LinkList();
tc->next->data = ta->data;
tc->next->next = NULL;
tc = tc->next;
ta = ta->next;
tb = tb->next;
}
else if (ta->data < tb->data)
ta = ta->next;
else
tb = tb->next;
}
return;
}
找出链表a和b的交集。
这个不难看出和上一题的思路是相同的,所以代码完全参考第十四题即可,如果说不同的地方的话,那就是,14题的代码,并没把其余节点释放空间,而15题需要把非公共节点释放掉。
判断表b是不是表a的连续子序列。
// p16 判断lb是否是la的连续子序列 no test
bool isAIncluedB(PLinkList la, PLinkList lb)
{
PLinkList ta = la->next, tb = lb->next;
PLinkList pre = la->next;
while (tb && ta){
if (ta->data == tb->data){
ta = ta->next;
tb = tb->next;
}
else
{
ta = pre->next;
tb = lb->next;
}
}
if (tb)
return false;
return true;
}
判断循环双链表是否对称。
#include
#include
#include
#include
using namespace std;
typedef int Elemtype;
typedef struct dnode{
Elemtype data;
struct dnode *pre, *next;
}DNode, *LDNode;
// 创建一个双向循环链表
void createDNode(LDNode &list, int len)
{
list = new DNode();
list->pre = list;
list->next = list;
LDNode tail = list;
for (int i = 0; i < len; i++)
{
LDNode tmp = new DNode();
tmp->data = rand() % 2;
tmp->next = tail->next;
tmp->pre = tail;
tail->next->pre = tmp;
tail->next = tmp;
tail = tmp;
}
return;
}
void printFrontToBack(LDNode list)
{
LDNode tmp = list->next;
while (tmp != list)
{
cout << tmp->data << " ";
tmp = tmp->next;
}
cout << endl;
return;
}
void printBackToFront(LDNode list)
{
LDNode tmp = list->pre;
while (tmp != list)
{
cout << tmp->data << " ";
tmp = tmp->pre;
}
cout << endl;
return;
}
// 是否对称
bool isSymmetry(LDNode list)
{
LDNode l = list->next, r = list->pre;
while (l != r && l->next != r)
{
if (l->data != r->data)
return false;
else
{
l = l->next;
r = r->pre;
}
}
if (l->next == r)
return l->data == r->data;
return true;
}
int main()
{
srand(time(0));
LDNode list = NULL;
createDNode(list, 4);
printFrontToBack(list);
printBackToFront(list);
if (isSymmetry(list))
cout << "对称" << endl;
else
cout << "不对称" << endl;
return 0;
}
都是循环单链表的题目,所以代码写到了一起。
18. 把两个循环单链表合并成一个。
19. 循环输出循环单链表中的最小值节点,并释放掉,直至表空。
#include
#include
#include
#include
using namespace std;
typedef int Elemtype;
typedef struct node
{
Elemtype data;
struct node *next;
}LNode, *PLNode;
// 创建循环单链表
void createCycleLNode(PLNode &list, int len)
{
list = new LNode();
list->next = list;
PLNode tail = list;
for (int i = 0; i < len; i++)
{
PLNode tmp = new LNode();
tmp->next = tail->next;
tmp->data = rand() % 10;
tail->next = tmp;
tail = tmp;
}
return;
}
// 输出循环单链表
void printCycleLNode(PLNode list)
{
PLNode tmp = list->next;
while (tmp != list)
{
cout << tmp->data << " ";
tmp = tmp->next;
}
cout << endl;
return;
}
// p18 把lb加到la上使之循环结构依旧成立
void addCycleLNode(PLNode &la, PLNode lb)
{
if (!lb->next) return;
PLNode taila = la, tailb = lb;
while (taila->next != la) taila = taila->next; // 找到a的尾巴
while (tailb->next != lb) tailb = tailb->next; // 找到b的尾巴
taila->next = lb->next;
tailb->next = la;
}
// p19 找出循环单链表的最小值的节点并删除
void printMinDel(PLNode &list)
{
PLNode pre = list;
PLNode tmp = list->next;
while (list->next != list)
{
pre = list;
PLNode t2 = list;
while (t2->next != list){
if (t2->next->data < pre->next->data) pre = t2;
t2 = t2->next;
}
cout << pre->next->data << " ";
PLNode del = pre->next;
pre->next = del->next;
free(del);
}
cout << endl;
}
int main()
{
srand(time(0));
PLNode list1 = NULL, list2 = NULL;
createCycleLNode(list1, 2);
createCycleLNode(list2, 5);
addCycleLNode(list1, list2);
printCycleLNode(list1);
printMinDel(list1);
return 0;
}
在结构体中加入freq,频率定义。
定义Locate(list,x)操作,把list中值为x的元素的freq++,并按照元素的freq属性,降序排序。
#include
#include
#include
using namespace std;
typedef int Elemtype;
typedef struct dnode
{
Elemtype data;
struct dnode *pre, *next;
int freq; // 频率
}DNode, *PDNode;
// 创建一个双向循环链表
void createDNode(PDNode &list, int len)
{
list = new DNode();
list->next = list;
list->pre = list;
PDNode tail = list;
for (int i = 0; i < len; i++)
{
PDNode tmp = new DNode();
tmp->next = tail->next;
tmp->pre = tail;
tmp->data = rand() % 10;
tmp->freq = 0;
tmp->next->pre = tmp;
tail->next = tmp;
tail = tmp;
}
return;
}
// 从前打印双向链表
void printFrontToBack(PDNode list){
PDNode tmp = list->next;
while (tmp != list)
{
cout << tmp->data << " ";
tmp = tmp->next;
}
cout << endl;
return;
}
// 从后往前打印双向链表
void printBackToFront(PDNode list)
{
PDNode tmp = list->pre;
while (tmp != list)
{
cout << tmp->data << " ";
tmp = tmp->pre;
}
cout << endl;
return;
}
void Locate(PDNode &list, Elemtype x)
{
PDNode tmp = list->next;
while (tmp != list)
{
if (tmp->data == x)
{
tmp->freq++;
PDNode p = tmp;
while (p->pre != list && p->freq >= p->pre->freq){
swap(p->data, p->pre->data);
swap(p->freq, p->pre->freq);
p = p->pre;
}
}
tmp = tmp->next;
}
return;
}
int main()
{
srand(time(0));
PDNode list = NULL;
createDNode(list, 20);
printFrontToBack(list);
while (true)
{
int n; cin >> n;
Locate(list, n);
printFrontToBack(list);
}
return 0;
}
查找链表中的倒数第k个元素。
// p21 查找倒数第k个元素
ElemType findLastK(PLinkList list, int k)
{
ElemType res;
int cnt = 0;
PLinkList tp = list->next;
PLinkList rp = tp;
while (tp)
{
if (cnt < k)
{
cnt++;
}
else
rp = rp->next;
tp = tp->next;
}
if (cnt == k)
return rp->data;
cerr << "error!" << endl;
return -1;
}
找到链表中的公共节点,和前面的第八题类似。
#include
#include
#include
using namespace std;
typedef char Elemtype;
typedef struct node{
Elemtype data;
struct node *next;
}StrList, *PStrList;
int len(PStrList list){
int cnt = 0;
PStrList tmp = list->next;
while (tmp)
{
cnt++;
tmp = tmp->next;
}
return cnt;
}
// 创造链表字符串
void createStrList(PStrList &list, string str)
{
list = new StrList(); list->next = NULL;
PStrList tail = list;
for (int i = 0; i < str.size(); i++)
{
PStrList p = new StrList();
p->next = tail->next;
p->data = str[i];
tail->next = p;
tail = p;
}
return;
}
// 输出链表字符串
void printStrList(PStrList list)
{
PStrList tmp = list->next;
while (tmp){
cout << tmp->data;
tmp = tmp->next;
}
cout << endl;
return;
}
// p22 找到公共节点
PStrList findPublicNode(PStrList la, PStrList lb)
{
PStrList res = NULL;
int lena = len(la), lenb = len(lb);
if (lena < lenb) { swap(la, lb); swap(lena, lenb); }
PStrList ta = la, tb = lb;
for (int i = 0; i < lena - lenb; i++) ta = ta->next;
while (ta->next){
if (ta->next == tb->next)
return ta->next;
ta = ta->next;
tb = tb->next;
}
return res;
}
void mergeList(PStrList &la, PStrList &lb)
{
int lena = len(la), lenb = len(lb);
PStrList ta = la, tb = lb, publicnodea = NULL, publicnodeb = NULL;
if (lena > lenb) for (int i = 0; i < lena - lenb; i++) ta = ta->next;
if (lenb > lena) for (int i = 0; i < lenb - lena; i++) tb = tb->next;
while (ta->next){
if (ta->next->data != tb->next->data)
{
publicnodea = ta->next;
publicnodeb = tb->next;
}
ta = ta->next;
tb = tb->next;
}
publicnodea->next = publicnodeb->next;
return;
}
int main()
{
PStrList list = NULL, list2 = NULL;
createStrList(list, "zhuyunpeng");
createStrList(list2, "sunrongxiaopeng");
mergeList(list, list2);
printStrList(list);
printStrList(list2);
PStrList publicnode = findPublicNode(list, list2);
if (publicnode == NULL)
cout << "未找到!" << endl;
else
cout << publicnode->data << endl;
return 0;
}
删除链表中的元素的绝对值重复的元素,要求|data| <= n。
// p23 删除重复元素,时间复杂度尽可能小, |data| <= n
void repeatElemtype(PLinkList &list, int n)
{
int *cnt = new int[n + 1];
memset(cnt, 0, sizeof(int) * (n + 1));
PLinkList tmp = list;
while (tmp->next)
{
int t = abs(tmp->next->data);
if (!cnt[t]) cnt[t]++, tmp = tmp->next;
else{
PLinkList del = tmp->next;
tmp->next = del->next;
free(del);
}
}
}