C语言 链表相关 操作


今天对单链表的相关操作做了学习,掌握了链表操作的基本知识,做一个记录:

// 链表操作.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"//预编译头 没关系
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct node
{
int element;

struct node * next;

}Node;


Node * CreatList(Node* Head);

void ListPrint(Node * Head);

void ClearList(Node *Head);

int SizeList(Node *Head);//注意 有返回值的函数调用 不能是void型 函数类型一定要与返回值一致

int GetElement(Node * Head,int index);

int FindElement(Node *Head,int Data);

//插入链表有三种方式 1.表头 2.表尾 3.表中间(1.以序号为查找 2.以元素值查找)

Node * InsertHeadElement(Node * Head,int Data);

Node * InsertTailElement(Node * Head,int Data);

Node * InsertIndexElement(Node *Head,int Index,int Data);

Node * InsertDataElement(Node *Head,int Target,int Data);


//删除链表和上面一样有三种 1.删除表头 2.删除表尾 3.删除中间

Node * DeleteHeadElement(Node * Head);

Node * DeleteTailElement(Node * Head);

Node * DeleteIndexElement(Node *Head,int Index);

Node * DeleteDataElement(Node *Head,int Target);

int main(void)
{
	
	Node *Head=NULL;//作为全局变量 链表的头指针 非常重要 之后的函数参数都是传递的这个


	Head=CreatList(Head);

	Head=DeleteHeadElement(Head);

	Head=DeleteTailElement(Head);


	Head=DeleteDataElement(Head,13);

	Head=InsertHeadElement( Head,255);

	Head=InsertTailElement(Head,255);

	Head=InsertIndexElement(Head,2,255);

	Head=InsertDataElement(Head,12,255);

	ListPrint(Head);

	Head=DeleteIndexElement(Head,3);

	ListPrint(Head);

	printf("链表大小为 %d\n",SizeList(Head));

	printf("链表第三个元素为 %d\n",GetElement(Head,3));

	if(FindElement(Head,4)==1)
		printf("\nfind element 4\n");
	else
		printf("\nnot find element 4\n");


	ClearList(Head);


	system("pause");

	return 0;
}




Node * CreatList(Node* Head)
   {
	printf("inpute linked list:\n");

	int temp=1;//该元素用来临时存放输入的数 和判断输入终止条件
	Node *p1,*p2;//两个元素分别指向新分配的元素和指向链表的最后一个元素

	while(temp>0)
	{

	p1=(Node *)malloc(sizeof(Node));//p1始终是指向新分配的元素
	if(p1==NULL) {printf("内存分配失败\n");return 0;}
	memset(p1,0,sizeof(Node));

	scanf("%d",&temp);//对新节点进行赋值
	p1->element=temp;
	p1->next=NULL;

	if(Head==NULL)
	{Head=p1;p2=p1;}//赋值的第三步首先判断 不管怎么样为了使得p2始终指向最后一个元素 都要把p2=p1
	else
		//Head->next=p1;//这样处理导致每一次分配只能在下一个 链表的总长度为2
	{p2->next=p1;
		p2=p1;//p2始终指向链表的最后一个元素
	}
	}

	return Head;
   }



 void ListPrint(Node * Head)
   {
    printf("\n链表元素为:\n");
	Node * p1;
	p1=Head;
	while(p1!=NULL)//将原来的p1->next!=NULL 改成这个防止最后一个节点漏掉
	{ 
	printf("%d\n",p1->element);
	p1=p1->next;
	}
   
   }




void ClearList(Node *Head)
{

	Node *p1,*p2;
	p1=Head;
	
	if(p1==NULL)
	{printf("KONG\n");return ;}
	else 
	{
	while(p1!=NULL)
	{	
	p2=p1->next;
	free(p1);
	p1=p2;
	}
	printf("已释放链表\n");
	}
}


int SizeList(Node *Head)
{

Node *p1=Head;
int size=0;

while(p1!=NULL)
{
p1=p1->next;
size++;
}

return size;
}

int GetElement(Node * Head,int index)
{
Node *p1=Head;
int id=0;

if(index<1) {printf("index error\n");return -2;}
if(p1==NULL) {printf("lianbiao kong\n");return -2;}
while(p1!=NULL)
{
id++;
if(id==index)
break;

p1=p1->next;

}

if(index>id) {printf("超出范围\n");return -2;}//超出范围

return p1->element;

}

int FindElement(Node *Head,int Data)
{
Node * p1=Head;

while(p1!=NULL)
{
if(p1->element==Data)
break;
p1=p1->next;
}
if(p1!=NULL)
return 1;
else
return 0;

}

Node * InsertHeadElement(Node * Head,int Data)
{
	Node *p1;

	p1=(Node *)malloc(sizeof(Node));
	if(p1==NULL) {printf("内存分配失败\n"); return Head;}
    memset(p1,0,sizeof(Node));

	p1->element=Data;
	p1->next=Head;
	Head=p1;

	return Head;

}

Node * InsertTailElement(Node * Head,int Data)
{
	Node *p1,*p2;

	p2=Head;//这句话一定要注意 不对变量进行赋值直接使用 显然是错的
	while(p2->next!=NULL)
	{
	p2=p2->next;//查找出表尾最后一个元素
	}

	p1=(Node *)malloc(sizeof(Node));
	if(p1==NULL) {printf("内存分配失败"); return Head;}
	memset(p1,0,sizeof(Node));

	p1->element=Data;

	p2->next=p1;

	return Head;
}

Node * InsertIndexElement(Node *Head,int Index,int Data)
{
	Node * p1,*p2;
	int i=0;

	p2=Head;
	while(p2!=NULL)
	{
		i++;
		if(Index==i)
			break;
		p2=p2->next;
	}

  //可以对输入的序号判断 包含1.大于等于1 超出范围等

	p1=(Node*)malloc(sizeof(Node));
	if(p1==NULL) {printf("内存分配失败");return Head;}
	memset(p1,0,sizeof(Node));//分配

	p1->element=Data;//赋值

	p1->next=p2->next;//插入 p1是新元素 p2是目标位置
	p2->next=p1;

	return Head;
}


Node * InsertDataElement(Node *Head,int Target,int Data)
{
	Node *p1,*p2=Head;


	while(p2!=NULL)//防止查找不到 先找 再分节点内存
	{
	if(p2->element==Target)
		break;
	p2=p2->next;
	
	}

	if(p2==NULL) {printf("Not Find %d cannt insert\n",Target);return Head;}

	p1=(Node*)malloc(sizeof(Node));
	if(p1==NULL) {printf("failed");return Head;}
	memset(p1,0,sizeof(Node));

	p1->element=Data;


	p1->next=p2->next;
	p2->next=p1;

	return Head;

}

Node * DeleteHeadElement(Node * Head)
{
	Node *p1;

	p1=Head;
	Head=Head->next;
	free(p1);

	return Head;
}

Node * DeleteTailElement(Node * Head)
{
	Node * p1,*p2;

	p1=Head;
	while(p1->next!=NULL)
	{
		p2=p1;
		p1=p1->next;
	}

	p2->next=NULL;
	free(p1);

	return Head;

}

Node * DeleteIndexElement(Node *Head,int Index)//注意 删除是找他上一个节点和当前节点 插入是找下一个节点和当前节点
{
	Node *p1=Head,*p2;
	int i=0;

	while(p1!=NULL)
	{

		p2=p1;		//p2表示当前的找到的节点 p1是指向下一个的节点
		p1=p1->next;

		i++;		//默认从1序号开始
		if(Index-1==i)//因为默认查找到的元素是当前元素和该元素的下一个元素,删除不方便 因此使用节点减一操作
		{break;}
			
	}

	p2->next=p1->next;
	free(p1);

	return Head;


}

Node * DeleteDataElement(Node *Head,int Target)
{
	Node *p1,*p2;
	p1=Head;

	while(p1!=NULL)//有bug版 没有该元素时候p1->element错误 空地址
	{
		p2=p1;
		p1=p1->next;

		if(p1->element==Target)
			break;
	}

	if(p1==NULL) {printf("cannot fint %d cannot deletl\n",Target);return Head;}

	p2->next=p1->next;

	free(p1);

	return Head;
}


下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、12、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这一功能。 首先,需要在资源设计工具中构建一个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入一个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值