数据结构-线性表(顺序表集合合并,链表,拉丁方阵,魔术师发牌问题等)
目录
线性表的顺序存储结构
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALESE 0
// status 是函数的类型,其值是函数结果的状态代码,如OK等
typedef int status;
// 线性表的顺序存储结构代码
const int Maxsize = 20;
typedef int Elemtype;
typedef struct
{
Elemtype data[Maxsize];
int length; // 线性表当前长度
}Sqlist;
// getelem函数
/*
list中第i个元素的值作为e返回
*/
status Getelem(Sqlist list,int i,Elemtype *e)
{
if(list.length == 0 || list.length < i)
{
return ERROR;
}
*e = list.data[i - 1];
return *e;
}
// listinsert函数
/*
list中第i个位置插入新元素e
*/
status Listinsert(Sqlist *list,int i,Elemtype e)
{
int k ;
if (list->length == Maxsize)
{
return ERROR;
}
if ( i < 0 || i > list->length + 1)
{
return ERROR;
}
if ( i <= list->length)
{
for ( int k = list->length - 1; k >= i - 1; k --)
{
list->data[ k + 1 ] = list->data[k];
}
}
list->data[i - 1] = e; // 将新元素插入,注意这里data下标是i - 1!
list->length ++ ; // 这一步不要忘记!
return OK;
}
//Listdelete
status Listdelete (Sqlist *list,int i,Elemtype e)
{
if(list->length == 0) // 第一次写的时候未考虑表为空的情况
{
return ERROR;
}
else if (i <= 0 || i > list->length) // 注意这两个条件是可以并起来的
{
return ERROR;
}
e = list->data[i - 1];
printf("已删除e!\n");
for(int k = i - 1; k <= list->length - 1; k ++)
{
list->data[k] = list->data[k + 1];
}
list->length --;
return OK;
}
// listprint函数
status Listprint(Sqlist *list)
{
printf("list: ");
for(int i = 0; i < list->length; i ++)
{
printf("%d ",list->data[i]);
}
printf("\n");
return OK;
}
int main()
{
printf("hello world!\n");
printf("------------------------------------------------------\n");
printf("|选择菜单:\n");
printf("|1.插入数字\n");
printf("|2.按照位置删除\n");
printf("------------------------------------------------------\n");
printf("请输入一个数字:\n");
//初始化一个list
Sqlist list ;
list.length = 0;
//输入操作
while(1)
{
int option;
scanf("%d",&option);
system("cls");
if(option == 1)
{
//输入1 listinsert
//插入元素
int cnt;
printf("请输入将要插入多少个元素:\n");
scanf("%d",&cnt);
for(int i = 1; i <= cnt ; i ++)
{
int e;
printf("请输入要插入的数字:\n");
scanf("%d",&e);
// printf("i = %d ,e = %d\n",i,e);
Listinsert(&list,i,e);
Listprint(&list);
}
}
else if (option == 2)
{
// 输入2 listdelete
system("cls");
printf("请输入要删除list中的第几个数字\n");
int deln;
scanf("%d",&deln);
int e = 0;
Listdelete(&list,deln,e);
Listprint(&list);
}
}
system("pause");
return 0;
}
顺序表实现集合合并(合并后冒泡排序)
/*
顺序表实现集合合并
*/
# include<stdlib.h>
# include<stdio.h>
# define OK 1
# define ERROR 0
# define Maxsize 100
typedef int Elemtype;
// 定义顺序表结构体
typedef struct list_struct
{
Elemtype *data;// 基坐标
int length; // 记录顺序表用到了哪里
}list_struct;
typedef list_struct *plist;
int list_init(plist list)
{
list->data = (Elemtype *) malloc(Maxsize * sizeof(Elemtype));
list->length = 0;
return OK;
}
int list_insert(plist list,Elemtype e)
{
list->data[list->length ++] = e;
return OK;
}
int list_delete(plist list,Elemtype e)
{
int j = -1;
for(int i = 0 ; i < list->length ; i ++)
{
if(list->data[i] == e)
{
j = i;
break;
}
}
while(j < list->length && j != -1)
{
// 覆盖掉即为删除
list->data[j] = list->data[j + 1];
j ++;
}
list->length --;
return OK;
}
int list_combine(plist lista,plist listb)
{
// 已经经过主函数处理,这里lista的长度已经比listb的长度大
// listb长度小,所以让listb插入到a中去
// 先删除重复元素
for(int i = 0 ; i < listb->length ; i ++)
{
for(int j = 0 ; j < lista->length ; j ++)
{
if(listb->data[i] == lista->data[j])
{
//删除 listb中的data[i]
list_delete(listb,listb->data[i]);
}
else continue;
}
}
// listb中剩下的插入lista
int listaidx = lista->length;
for(int i = 0 ; i < listb->length ; i ++)
{
lista->data[listaidx ++] = listb->data[i];
lista->length ++;
}
return OK;
}
int list_printf(plist list)
{
for(int i = 0 ; i < list->length ; i ++)
{
printf("%d-",list->data[i]);
}
printf("\n");
return OK;
}
// 冒泡排序
int list_sort(plist list)
{
for(int j = 0; j < list->length ; j ++)
{
for(int i = 0 ; i < list->length - j - 1 ; i ++) // 这里要多减去一个1,因为本来最后的一个下标是list->length - 1 而不是list->length,这里是i从0开始,因为最大的一定放到了最后面,所以后面j个一定是最大的了不用去继续排序,而前面是小的仍要从0开始
{
if( list->data[i] > list->data[i + 1] )
{
int n = list->data[i];
list->data[i] = list->data[i + 1];
list->data[i + 1] = n;
// printf("冒泡排序:%d和%d已经交换\n",list->data[i + 1],list->data[i]);
}
}
}
return OK;
}
int main()
{
int an,bn,e;
plist lista = (plist)malloc(sizeof(list_struct));
plist listb = (plist)malloc(sizeof(list_struct));
list_init(lista);
list_init(listb);
printf("请输入集合a中元素个数\n");
scanf("%d",&an);
printf("请输入集合a中的元素\n");
while(an --)
{
scanf("%d",&e);
list_insert(lista,e);
}
printf("请输入集合b中元素个数\n");
scanf("%d",&bn);
printf("请输入集合b中的元素\n");
while(bn --)
{
scanf("%d",&e);
list_insert(listb,e);
}
if(lista->length > listb->length)
{
list_combine(lista,listb);
printf("合并并排序后的集合为:");
list_sort(lista);
list_printf(lista);
}
else
{
list_combine(listb,lista);
printf("合并并排序后的集合为:");
list_sort(listb);
list_printf(listb);
}
// printf("listb为:");
// list_printf(listb);
// list_sort(listb);
system("pause");
return 0;
}
线性表的链式存储结构
单链表
// 单链表
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALESE 0
typedef int status;
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
Node *next;
}Node;
typedef struct Node *Linklist;
Linklist chainlist_creat(void)
{
Linklist headnode = (Linklist)malloc(sizeof(Node)); // 这里必须使用molloc函数去为结点申请内存空间,这样才会返回一个指向该块内存的指针,我们才能找到那块内存。堆储存区的内存是可以自由使用的,但是在不使用的时候就要记得free。栈储存区的在函数运行完会自动回收内存
Linklist list = headnode; // 这里直接创建了一个指向node类型的指针(头指针),并将它初始化了。
/*
headnode是一个指向头结点类型的指针
*/
headnode->next = NULL;
headnode->data = 0; // 储存链表长度
return list;
}
// 链表插入
status chainlist_insert(Linklist list, Elemtype e, int i)
{
Linklist p;
p = list;
int j = 0;
while(j < i && p)
{
p = p->next;
j ++;
}
if (!p)
{
printf("p为null\n");
return ERROR;
}
Linklist pnewnode = (Linklist)malloc(sizeof(Node));
pnewnode ->data = e;
pnewnode ->next = p->next;
p->next = pnewnode;
list->data ++;
printf("链表现在长度为:%d\n",list->data);
return OK;
}
// 链表打印
status chain_printf(Linklist list)
{
printf("链表为:\n");
Linklist p = list->next;
while(p)
{
printf("%d-",p->data);
p = p->next;
}
printf("\n");
return OK;
}
// 链表查找
status chain_find(Linklist list,int i,Elemtype *e)
{
Linklist p = list->next;
int j = 1;
while(p && j < i)
{
p = p->next;
j ++;
}
if (!p)
{
return ERROR;
}
*e = p->data;
return OK;
}
// 单链表删除
status chain_del(Linklist list,int i)
{
Linklist p;
p = list;
int j = 1;
while( j < i && p)
{
p = p->next;
printf("删除操作——遍历到%d\n",p->data);
j ++;
}
if( !p )
{
return ERROR;
}
int e;
Linklist q = p->next;
e = q->data;
printf("第%d个元素%d已删除!\n",i,e);
p->next = p->next->next;
list->data --;
free(q);
return OK;
}
int main()
{
Linklist list = chainlist_creat();
while(1)
{
printf("-------------------------菜单---------------------\n");
printf("0.清屏\n");
printf("1.在第i个位置后面插入新元素e\n");
printf("2.按位置查找,输出第i位置的元素e\n");
printf("3.删除链表中第i个位置的元素\n");
printf("--------------------------------------------------\n");
int op;
scanf("%d",&op);
if(op == 1)
{
int i,e;
printf("请输入i、e的值(想把新元素插入到第一个位置请输入0 e)\n");
scanf("%d %d",&i,&e);
chainlist_insert(list,e,i);
printf("插入完成!\n");
chain_printf(list);
}
else if (op == 2)
{
int i,*e;
printf("请输入i的值\n");
scanf("%d",&i);
chain_find(list,i,e);
printf("%d\n",*e);
}
else if(op == 3)
{
int i;
printf("请输入i的值\n");
scanf("%d",&i);
chain_del(list,i);
chain_printf(list);
printf("\n");
}
else if(op == 0)
{
system("cls");
}
}
return 0;
}
静态链表
/*
静态链表,双数组实现。
下面的写法很简洁,但是是具有局限性的,首先它删除的结点就不能free利用。还有分头插尾插。。。。。
*/
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
const int N = 10000;
int head,e[N],ne[N],idx; //head 指针指向头结点 e[]数组保存的是链表中的数,ne[]中是next指针,俩个通过下标关联起来,idx保存的是内存用到了哪个位置
int initlist(void)
{
head = -1; // 头指针指向-1,链表为空
idx = 0; // 内存用到了0
return OK;
}
int Lengthlist(void)
{
if(head == -1) return 0;
int p = e[head];
int cnt = 0;
while( p > 0)
{
p = ne[p]; // 将指针的值赋值给p,若p为-1退出循环
cnt ++;
}
return cnt;
}
int add_to_head(int x)
{
e[idx] = x; // e[idx]就是新的内存 这里将新的元素e存入新申请的内存
ne[idx] = head; // e[idx] 指向head的值,head 是指针,指向的是第一个结点。head的值就是第一个结点的位置(下标)
head = idx ++; // head 指向idx 然后将idx ++ (下一次申请新内存直接ne[idx]即可)
return OK;
}
// 在第K个位置的后面插入元素e
int insert_to_list(int k,int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx ++; // 这里注意,结点k的next指针应该指向的是 新结点 ,而新结点的位置(下标)就是idx,所以就直接是idx赋值给 k结点的next指针,idx ++ 是为了malloc新的“内存”
return OK;
}
int remove_head(void)
{
head = ne[head];
return OK;
}
// 移除第k个位置的后继结点
int remove(int k)
{
ne[k] = ne[ne[k]];
return OK;
}
int printflist(void)
{
int p = head;
printf("链表为:\n");
while(p >= 0)
{
printf("%d-",e[p]);
p = ne[p];
}
printf("\n");
return OK;
}
int main()
{
initlist();
while (1)
{
printf("--------------------menu-----------------------\n1.从头部插入\n2.在第k个结点后面插入元素x\n3.删除第K个结点后面的一个结点\n-----------------------------------------------------------------\n");
int op;
scanf("%d",&op);
if(op == 1)
{
int x;
printf("请输入x的值:\n");
scanf("%d",&x);
add_to_head(x);
printflist();
}
else if(op == 2)
{
int k,x;
printf("注意此方法不能插在头部和尾部!!!\n");
printf("请输入k、x的值:\n");
scanf("%d%d",&k,&x);
insert_to_list(k,x);
printflist();
}
else if(op == 3)
{
int k;
printf("请输入k的值:\n");
scanf("%d",&k);
remove(k);
printflist();
}
}
return 0;
}
作业:如何快速得到单链表的中间结点
思路:快慢指针
// 作业1
// 随机生成20个随机数的链表,使用快慢指针得到中间元素的值
# include<stdio.h>
# include<stdlib.h>
# include<time.h>
// 返回一个1 - 100之内的数字
int my_rand(void)
{
srand((unsigned)time(0) + rand());
int a = rand() % 100;
return a;
}
// 定义一个结点
typedef struct Node
{
int data;
Node *next;
}Node;
typedef Node *Link_list;
// 生成20个随机数链表,返回头指针
Link_list get_chain(void)
{
Link_list p = NULL;
//头结点
Link_list head = (Link_list)malloc(sizeof(Node));
p = head;
head->next = NULL;
// 头插法插入结点
for(int i = 0; i < 20; i ++)
{
Link_list node = (Link_list)malloc(sizeof(Node));
node->data = my_rand();
node->next = head->next;
head->next = node;
printf("%d-",node->data);
}
printf("\n");
return head;
}
// 获得链表中间值的快慢指针法
int get_chain_midelm(Link_list p)
{
p = p->next; //指向第一个结点
Link_list fast_p = p;
Link_list slow_p = p;
while(fast_p)
{
// printf("遍历到结点的data = %d\n",fast_p->data);
fast_p = (fast_p->next)->next;
slow_p = slow_p->next;
}
int mid = slow_p->data;
printf("mid = %d\n",mid);
return mid;
}
int main()
{
Link_list listp = get_chain();
get_chain_midelm(listp);
system("pause");
return 0;
}
单向循环链表
# include<stdlib.h>
# include<stdio.h>
# define OK 1
# define ERROR 0
typedef struct Node
{
int data;
Node *next;
}Node;
typedef Node* Link_list;
// 单向循环链表初始化
Link_list clist_init(void)
{
Link_list list; // 链表名作为头指针 但是单向循环链表的头指针是指向尾结点的。或者我们称之为尾指针
Link_list head = (Link_list)malloc(sizeof(Node));// 申请一个头结点
if(head == NULL) exit(0); // 如果申请失败就 退出
head->next = head; // 让头结点指向自己,就是一个链表为空的单向循环链表链表
list = head;
return list; // 返回尾指针
}
int clist_length(Link_list list)
{
int length = 0;
for(Link_list pnode = list; pnode->next != list; )
{
pnode = pnode->next;
length ++;
}
return length;
}
//向单向链表头部插入新元素e
void clist_insert_head(Link_list list,int e)
{
Link_list newnode = (Link_list)malloc(sizeof(Node));
newnode->data = e;
newnode->next = list->next;
list->next = newnode;
}
//打印链表
void clist_printf(Link_list list)
{
printf("链表为:\n");
for(Link_list p = list;p->next !=list;)
{
p = p->next;
printf("%d-",p->data);
}
printf("\n");
}
// 在单向链表中从尾部插入新的元素e
void clist_insert_end(Link_list list,int e)
{
Link_list newnode = (Link_list)malloc(sizeof(Node));
newnode->data = e;
Link_list p = list;
while(p->next != list) p = p->next; // 找到了尾结点的前一个结点,并用p指针指向了它
p->next = newnode;
newnode->next = list;
}
// 在单向循环链表中第i个位置之后插入元素e(即将元素插入到第i + 1个元素),注意不能涉及到从头插入或从尾部插入!!!
int clist_insert(Link_list list,int e,int i)
{
if(i < 0 || i > clist_length(list))
{
printf("i值错误!\n");
return ERROR;
}
Link_list newnode = (Link_list)malloc(sizeof(Node));
newnode->data = e;
// 使指针遍历到第i个结点(p此时指向的就是第i个结点)
Link_list p = list;
for(int k = 0; k < i; k ++)
{
p = p->next;
}
// 开始插入
newnode->next = p->next;
p->next = newnode;
return OK;
}
// 删除链表的第i个元素
int clist_remove(Link_list list,int i)
{
Link_list p = list;
for(int k = 0;k < i - 1; k ++)
{
p = p->next;
}
Link_list r_p = p->next;
p->next = p->next->next;
free(r_p);
return OK;
}
int main()
{
Link_list list = clist_init();
while(1)
{
printf("=======================================================\n");
printf("请输入操作数:\n1.向链表头部插入新元素e\n2.输出链表的长度\n3.在链表尾部插入新的元素\n4.在第i个元素后面插入新的元素e\n5.删除第i个结点\n...\n");
printf("=======================================================\n");
int op;
scanf("%d",&op);
if(op == 1)
{
int e;
printf("请输入元素e的值:\n");
scanf("%d",&e);
clist_insert_head(list,e);
clist_printf(list);
}
else if(op == 2)
{
int length = clist_length(list);
printf("链表的长度为:%d\n",length);
}
else if(op == 3)
{
int e;
printf("请输入元素e的值:\n");
scanf("%d",&e);
clist_insert_end(list,e);
clist_printf(list);
}
else if(op == 4)
{
int i,e;
printf("请输入i、e的值:\n");
scanf("%d%d",&i,&e);
clist_insert(list,e,i);
clist_printf(list);
}
else if(op == 5)
{
int i;
printf("请输入要删除的结点i的值:\n");
scanf("%d",&i);
clist_remove(list,i);
clist_printf(list);
}
}
system("pause");
return 0;
}
单向循环链表练习-约瑟夫环问题
// 约瑟夫环问题
/*
一共41人围成一个圈,开始报数,每个报3的人自杀,求出这41个人自杀顺序编号输出
-----循环列表解决
*/
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALSE 0
// 每个人为一个结点,idx是这个人的编号
typedef struct Node
{
int idx;
Node *next;
}Node;
typedef Node *Clink_list;
Clink_list cylist;
int clist_init(void)
{
Clink_list end_node = (Clink_list)malloc(sizeof(Node));
end_node->idx = 41;
end_node->next = end_node;
cylist = end_node;
for(int i = 40;i >=1;i --)
{
Clink_list new_node = (Clink_list)malloc(sizeof(Node));
new_node->idx = i;
new_node->next = end_node->next;
end_node->next = new_node;
}
return OK;
}
void clist_printf(void)
{
Clink_list p = cylist->next;
while(p->next != cylist->next)
{
printf("%d-",p->idx);
p = p->next;
}
printf("%d",p->idx);
printf("\n");
}
// 一直遍历链表,将答案输出
void answer_clist_remove(void)
{
Clink_list p = cylist->next;
int i = 1,cnt = 1;
while(p != NULL)
{
// 每当轮到人报数2,他的下一个人必定报3自杀
if(i == 2)
{
Clink_list throw_p = p->next;
p->next = p->next->next; // 直接绕过即可,然后下一个人报数1
printf("%d:编号为%d的人自杀\n",cnt ++ ,throw_p->idx);
free(throw_p);
}
i ++;
if(i == 3) i = 1;
p = p->next;
if(p->next == p)
{
printf("最后一个人编号为%d\n",p->idx);
break;
}
}
}
int main()
{
clist_init();
clist_printf();
answer_clist_remove();
system("pause");
return 0;
}
单向循环链表练习2-约瑟夫环问题升级版
// 约瑟夫环问题-升级版
/*
有1-N个人,每个人手中有一个密码(正整数m,可以控制输入),然后从第一个人开始,第一个人手中的密码为m1
,开始报数,当谁报的数为第一个人手中的密码数字m1时,他就自杀,自杀的这个人手中的密码m'为新的自杀数。
输出每个自杀的人的编号
*/
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALSE 0
typedef struct Node
{
int idx; // 这个人的序号值
Node *next;
int m_number; // 这个人手中的密码
}Node;
typedef Node *Clink_list;
Clink_list clist;
Clink_list clist_init(void)
{
printf("链表初始化:\n");
Clink_list head = (Clink_list)malloc(sizeof(Node));
head->idx = 1;
int pwd;
printf("请输入第1个人的密码设为?\n");
scanf("%d",&pwd);
head->m_number = pwd;
head->next = head;
clist = head;
return clist;
}
// 传入数据n个人,将剩下的n-1个人插入到循环列表中
// 尾插法
int clist_init_2(int n)
{
for(int i = 1;i < n ; i ++)
{
int n_nbr;
printf("请设置第%d个人的密码是?\n",i + 1);
scanf("%d",&n_nbr);
Clink_list newnode = (Clink_list)malloc(sizeof(Node));
newnode->idx = i + 1;
newnode->m_number = n_nbr;
newnode -> next = clist -> next; // clist表示的就是尾结点
clist->next = newnode;
clist = newnode;
}
return OK;
}
int clist_printf()
{
Clink_list p = clist -> next;
while(p->next != clist)
{
printf("第%d个人,密码是:%d\n",p->idx,p->m_number);
p = p->next;
}
printf("第%d个人,密码是:%d\n",p->idx,p->m_number);
p = p->next; // 上面只是循环到了clist(尾结点)的前一个结点,所以要再走一步输出
printf("第%d个人,密码是:%d\n",p->idx,p->m_number);
return OK;
}
int clist_remove(void)
{
Clink_list p = clist->next;
int k = 1; // 记录每个人报数
int cnt = 1; // 记录每个人的序号
int m = p->m_number;
while(p->next != p) // 只剩自己一个人的时候退出
{
// p 真杀他自己
if (m == 1)
{
// 使用一个新指针q来遍历到 要自杀的p的前一个结点,从而实现对p的绕过
Clink_list q = clist;
while(q->next != p)
{
q = q->next;
}
Clink_list cut_p = q->next;
// 如果要删除的结点是尾结点,需要将尾结点的指针前移
if(q->next->idx == clist->idx)
{
clist = q;
}
q->next = q->next->next;
p = p->next;
printf("第%d个自杀的人的序号是%d,他的密码是%d\n",cnt ++,cut_p->idx,cut_p->m_number);
m = cut_p->m_number;
free(cut_p);
k = 1;
}
else if(k == m - 1) // 如果报数到 m - 1,则下一个人需要被自杀,即这时候p的下一个结点需要被删掉
{
Clink_list cut_p = p->next;
if(p->next->idx == clist->idx)
{
clist = p;
}
p->next = p->next->next;
printf("第%d个自杀的人的序号是%d,他的密码是%d\n",cnt ++,cut_p->idx,cut_p->m_number);
m = cut_p->m_number;
free(cut_p);
p = p->next;
k = 1;
}
else
{
k++;
p = p->next;
}
}
printf("第%d个自杀的人的序号是%d,他的密码是%d\n",cnt ++,p->idx,p->m_number);
return OK;
}
int main()
{
clist_init();
printf("一共有n个人,请输入n的值:\n");
int n;
scanf("%d",&n);
clist_init_2(n);
clist_printf();
clist_remove();
system("pause");
return 0;
}
两个单向循环链表的合并
/*
将两个单向循环链表链接在一起
*/
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define FALSE 0
# define TRUE 1
typedef struct Node
{
int data;
Node * next;
}Node;
typedef Node *Clink_list;
// 初始化循环链表,传入循环链表名字,返回循环链表名字
Clink_list clist_init(Clink_list clist)
{
// 先设置尾结点
Clink_list end_node = (Clink_list)malloc(sizeof(Node));
end_node -> data = 10;
end_node -> next = end_node;
for(int i = 9; i >= 1; i --)
{
Clink_list p = (Clink_list)malloc(sizeof(Node));
p->data = i;
p->next = end_node->next;
end_node->next = p;
end_node = p;
}
clist = end_node;
return clist;
}
int clist_printf(Clink_list clist)
{
int clength = 1;
printf("链表为:");
Clink_list p;
for(p = clist->next; p != clist;p = p->next) // p遍历到维结点就立马退出了,所以尾结点需要单独输出一次并length++
{
printf("%d-",p->data);
clength ++;
}
printf("%d-",p->data);
printf("\n");
printf("该链表长度为%d\n",clength ++);
return OK;
}
Clink_list clist_combine(Clink_list lista,Clink_list listb)
{
Clink_list ahead = lista->next;
lista->next = listb->next;
listb->next = ahead;
return listb;
}
int main(void)
{
// 初始化
Clink_list clist_a = clist_init(clist_a);
Clink_list clist_b = clist_init(clist_b);
clist_printf(clist_a);
clist_printf(clist_b);
Clink_list clist_c = clist_combine(clist_a,clist_b);
clist_printf(clist_c);
system("pause");
return 0;
}
判断链表是否有环
/*
判断单链表中是否有环:
双指针算法,使用快慢双指针。
指针p q 同时开始遍历,一个移动1一个移动2,当p == q 真值为1的时候说明有环
*/
// 这里做一个单向循环列表,一个单向链表用来判断
# include<stdio.h>
# include<stdlib.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALSE 0
typedef struct Node
{
int data;
Node *next;
}Node;
typedef Node *Link_list;
Link_list list_init(Link_list list)
{
Link_list head_node = (Link_list)malloc(sizeof(Node));
head_node->data = 10;
head_node->next = NULL;
for(int i = 9;i >= 1; i --)
{
Link_list node = (Link_list)malloc(sizeof(Node));
node->data = i;
node->next = head_node;
head_node = node;
}
list = head_node;
return list;
}
int list_printf(Link_list list)
{
Link_list p = list;
printf("单向链表为:");
while(p != NULL)
{
printf("%d-",p->data);
p = p->next;
}
printf("\n");
return OK;
}
Link_list clist_init(Link_list clist)
{
Link_list end_node = (Link_list)malloc(sizeof(Node));
end_node->data = 10;
end_node->next = end_node;
clist = end_node;
for(int i = 9;i >= 1; i --)
{
Link_list new_node = (Link_list)malloc(sizeof(Node));
new_node->data = i;
new_node->next = end_node->next;
end_node->next = new_node;
}
return clist;
}
int clist_printf(Link_list clist)
{
Link_list p = clist->next;
printf("链表为:");
while(p != clist)
{
printf("%d-",p->data);
p = p->next;
}
printf("%d-\n",p->data);
return OK;
}
// 返回0或1,0代表无环,1代表有环
int judge_loop(Link_list list)
{
int judge = 0; // 0代表无环,1代表有环
Link_list fast_p = list;
Link_list slow_p = list;
while(slow_p != NULL )
{
fast_p = fast_p->next;
if(fast_p == NULL) break;
fast_p = fast_p->next;
if(fast_p == NULL) break;
slow_p = slow_p->next;
if(fast_p == slow_p)
{
judge = 1;
break;
}
}
return judge;
}
int main()
{
Link_list lista; // 单向链表
lista = list_init(lista);
list_printf(lista);
Link_list clista;
clista = clist_init(clista);
clist_printf(clista);
int jud_clist = 0,jud_list = 0;
jud_list = judge_loop(lista);
jud_clist = judge_loop(clista);
printf("clista有无环:%d\nlista有无环:%d\n",jud_clist,jud_list);
system("pause");
return 0;
}
★魔术师发牌问题★
首先手动模拟一下,思路见代码
一个思想,假设是正确的。假设我们的循环链表就是正确的答案。
/*
魔术师发牌问题:
魔术师将A 2 3 4 5 6 7 8 9 10 J Q K十三张牌按照一定顺序叠放好,将有花色的一面朝下。
第一次,魔术师开始数数,数1,停止数数。将最上面的牌翻过来,然后将其放在桌面上展示,是A。
第二次,魔术师开始数数,数1,2,停止数数。将牌顶的第一张牌放到牌堆最下方,第二张牌翻过来,然后将其放在桌面上展示,是2。
第三次,魔术师开始数数,数1,2,3,停止数数。将牌顶的第一二张牌放到牌堆最下方,第三张牌翻过来,然后将其放在桌面上展示,是3。
......
直到将所有的牌亮出来为止,问原来的顺序是怎么样的?
*/
# include<stdlib.h>
# include<stdio.h>
# define OK 1
# define ERROR 0
# define TRUE 1
# define FALSE 0
typedef struct Node
{
int idx;
int data;
Node *next;
}Node;
typedef Node *Clink_list;
// 初始化循环列表
Clink_list magic_clist_init(Clink_list clist)
{
Clink_list end_node = (Clink_list)malloc(sizeof(Node));
end_node->data = 0;
end_node->idx = 13;
end_node->next = end_node;
clist = end_node;
for(int i = 1 ; i <= 12; i ++) // 由于只有13张牌,所以这里就直接使用数值13.如果扑克牌有14、15等等,把这里的12改成13、14等等即可
{
Clink_list new_node = (Clink_list)malloc(sizeof(Node));
new_node->data = 0;
new_node->idx = i;
Clink_list p = end_node->next;
while(p->next != end_node)
{
p = p->next;
}
p->next = new_node;
new_node->next = end_node;
}
return clist;
}
int clist_count(Clink_list clist)
{
Clink_list p = clist->next;
int cnt = 0;
// printf("链表:");
while(p != clist)
{
// printf("%d-",p->data);
cnt ++;
p = p->next;
}
// printf("%d\n",p->data);
// printf("循环链表中有%d个元素\n",++ cnt);
return ++cnt;
}
/*
假设我的链表中的每一个结点的data的值就是正确的顺序。
向循环链表中的结点添加data = see_n(将要翻过来牌的数),然后将这个结点remove掉
*/
int mclist_remove(Clink_list clist)
{
int speak_n = 1,see_n = 1;//speak_n表示魔术师的报数,see_n表示下一个翻过来的牌的数,order_n表示正确排序的第几张牌
Clink_list p = clist->next; // p去遍历
while(p)
{
for(speak_n = 1;speak_n < see_n ; speak_n ++)
{
p = p->next;
}
p->data = see_n ++;
printf("牌堆中第%d牌应该是%d\n",p->idx,p->data);
//删除结点
Clink_list cut_p = p,q = clist->next;
// 使用q遍历到想要删除的结点p前面的一个结点
while(q->next != cut_p)
{
q = q->next;
}
// 对p结点绕过
q->next= q->next->next;
if(clist_count(clist) == 1) break;
p = q->next;
// printf("p->data = %d\n",p->data);
free(cut_p);
}
p = p->next;
p->data = see_n ++;
printf("牌堆中第%d牌应该是%d\n",p->idx,p->data);
return OK;
}
int main()
{
Clink_list clist;
clist = magic_clist_init(clist);
clist_count(clist);
mclist_remove(clist);
system("pause");
return 0;
}
拉丁方阵问题
/*
拉丁方阵是一种n×n的方阵,方阵中恰有n中不同的元素,每种元素恰有n个,并且每种元
素在一行和一列中恰好出现一次。著名数学家和物理学家欧拉使用拉丁字母来做为方阵里元素
的符号,拉丁方阵因此而得名。
*/
# include<stdio.h>
# include<stdlib.h>
typedef struct Node
{
int data;
Node *next;
}Node;
typedef Node *Clink_list;
Clink_list clist_init(Clink_list clist)
{
Clink_list end_node = (Clink_list)malloc(sizeof(Node));
clist = end_node;
end_node->data = 9;
end_node->next = end_node;
for(int i = 1;i <= 8; i ++)
{
Clink_list new_node = (Clink_list)malloc(sizeof(Node));
new_node->data = i;
Clink_list p = end_node;
while(p->next != end_node)
{
p = p->next;
}
new_node->next = end_node;
p->next = new_node;
}
return clist;
}
void latin_printf(Clink_list clist)
{
printf("latin:\n");
int k = 9;
while(k --)
{
Clink_list p = clist->next;
while(p != clist)
{
printf("%d ",p->data);
p = p->next;
}
printf("%d\n",p->data);
clist = clist->next;
}
}
int main()
{
Clink_list clist ;
clist = clist_init(clist);
latin_printf(clist);
system("pause");
return 0;
}
双向循环链表
/*
双向链表
初始化
插入
删除
输出
*/
# include<stdio.h>
# include<stdlib.h>
typedef struct Node
{
int data;
Node *prior;
Node *next;
}Node;
typedef Node *Doublelink_list;
Doublelink_list doublelist_init(Doublelink_list dlist)
{
Doublelink_list head_node = (Doublelink_list)malloc(sizeof(Node));
dlist = head_node;
Doublelink_list end_node = (Doublelink_list)malloc(sizeof(Node));
head_node->data = 0;
end_node->data = 0;
head_node->next = end_node;
head_node->prior = end_node;
end_node->next = head_node;
end_node->prior = head_node;
return dlist;
}
int doublelist_length(Doublelink_list dlist)
{
int length = 0;
for(Doublelink_list p = dlist;p != dlist->prior ; p = p->next)
{
length ++ ;
}
length ++ ;
return length;
}
// 在第i个元素之后插入元素e
Doublelink_list doublelist_insert(Doublelink_list dlist,int i,int e)
{
if(i <= doublelist_length(dlist) - 2 && i >= doublelist_length(dlist))
{
printf("双向链表与长度与输入的i不符!\n");
exit(1);
}
Doublelink_list p = dlist;
// 使用p指针遍历到第i个结点本身
for(int k = 1;k < i ;k ++)
{
p = p->next;
}
// 插入
Doublelink_list new_node = (Doublelink_list)malloc(sizeof(Node));
new_node->data = e;
new_node->next = p->next;
new_node->prior = p;
p->next->prior = new_node;
p->next = new_node;
return dlist;
}
// 删除第i个位置的元素,并返回其值e
int doublelist_delete(Doublelink_list dlist,int i)
{
if(i >= doublelist_length(dlist) && i <= 1)
{
printf("链表长度与i的值不符!\n");
exit(1);
}
Doublelink_list p = dlist;
// 先使用p指针遍历到第i个元素的前一个元素
for(int k = 1; k < i - 1; k ++)
{
p = p->next;
}
Doublelink_list cut_p = p->next;
p->next->prior = p;
p->next = p->next->next;
int e = cut_p->data;
printf("被删掉的元素是%d\n",e);
free(cut_p);
return e;
}
void doublelist_printf(Doublelink_list dlist)
{
Doublelink_list p = dlist;
printf("链表为:");
while(p != dlist->prior)
{
printf("%d-",p->data);
p = p->next;
}
printf("%d\n",p->data);
}
int main()
{
Doublelink_list dlist;
dlist = doublelist_init(dlist);
int dlist_length = doublelist_length(dlist);
printf("%d\n",dlist_length);
printf("插入操作:请输入插入操作的个数?\n");
int cnt = 0;
scanf("%d",&cnt);
while(cnt --)
{
int i,e;
printf("请输入要在第几个元素后面插入?插入元素的值是多少?\n");
scanf("%d%d",&i,&e);
doublelist_insert(dlist,i,e);
doublelist_printf(dlist);
}
printf("删除操作:请输入删除操作的个数?\n");
scanf("%d",&cnt);
while(cnt --)
{
int i;
printf("请输入要删除第几个元素?\n");
scanf("%d",&i);
doublelist_delete(dlist,i);
doublelist_printf(dlist);
}
system("pause");
return 0;
}
rds_blogs