文章目录
C代码实现
一、 逆序输出
题目:逆序输出,当输入-1时表示输入结束。
1. 使用不带头结点的头插入法创建链表实现
每创建一个结点,都使该结点成为头结点,这样头结点不断地向前移动,就可以创建一个没有特定头结点的链表。首先创建的结点,会出现在整个链表的最末端,所以数据的写入是逆序的。
【注意:开始的时候,head要初始化为NULL】
#include<stdio.h>
#include<stdlib.h>
struct list_node
{
int data;
struct list_node *next;
};
int main()
{
struct list_node *head,*p,*b,*s,*t;
int n;
head=NULL;
while(1)
{
scanf("%d",&n);
if(n==-1)
break;
p=(struct list_node *)malloc(sizeof(struct list_node));
p->data=n;
p->next=head;
head=p;
}
t=head;
while(t!=NULL)
{
printf("%d ",t->data);
t=t->next;
}
return 0;
}
开始时候,head 是一个空指针,创建一个结点p。现在head是指向一个链表的头结点,创建了一个新的结点p,向前插入。所以要p->next = head;然后再使head成为新链表的头结点。
2. 创建双向链表实现
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef struct DOUBLE_LIST
{
int data;
struct DOUBLE_LIST *prev;
struct DOUBLE_LIST *next;
}double_list;
double_list *createlist() //创建有n个元素的双向链表 并输入元素
{
double_list *head, *p, *q;
int n,x;
head = (double_list *)malloc(sizeof(double_list));
head->prev = head;
head->next = head;
p = head;
while(1){
scanf("%d", &x);
if(x==-1)
break;
q = (double_list *)malloc(sizeof(double_list));
q->data = x;
p->next = q;
head->prev = q;
q->prev = p;
q->next = head;
p = q;
}
return head;
}
//遍历并且输出这些元素
void printlist(double_list *head)
{
double_list *p;
p = head;
p = p->prev;
while(p!=head)
{
printf("%d ", p->data);
p = p->prev;
}
//printf("\n");
}
int main()
{
double_list *head;
head = createlist();
printlist(head);
return 0;
}
二、 删除单链表的第i个元素
/*
title : demo solution to problem 1387
author : John
date : 2014.1.9
last modify : 2014.1.9
*/
#include <stdio.h>
#include <stdlib.h>
// 定义链表数据类型
typedef struct LinkList{
int value;
struct LinkList *next;
}LL;
LL *mylinklist; // 单链表
int lcount; // 单链表元素个数
int N; // 单链表共有n个节点
int I; // 要删的元素的位置
// 从左到右输出链表元素
void printlist()
{
LL *p = mylinklist;
while( p )
{
printf( "%d ", p->value );
p = p->next;
}
//printf( "\n" );
}
// 读数据,建链表
int readin()
{
int va; // 读入的元素值
LL *tt; // 临时节点
LL *last; // 链尾指针
scanf( "%d%d", &N, &I );
lcount = N;
for( int kk=0 ; kk < N; kk++ )
{
scanf( "%d", &va );
tt = (LL *)malloc( sizeof(LL) );
if( !tt ) // 申请节点空间失败
return -1;
tt->value = va;
tt->next = NULL;
if( kk == 0 ) // 链首节点,特殊处理
{
mylinklist = tt;
last = tt;
}
else // 其他节点
{
last->next = tt;
last = tt;
}
}
return 0;
}
// 删除单链表L上的第i个数据节点
int Del_LinkList( int i )
{
if( i < 1 || i > lcount ) // 删除的位置有误
{
printf( "nothing to do" );
return 0;
}
if( i == 1 ) // 删除链头
{
LL *s = mylinklist; // 链首节点
mylinklist = mylinklist->next;
free(s); // 释放*s
lcount --;
printlist();
return 0;
}
LL *p = mylinklist;
int cc = 1;
while( p && cc < i-1 ) // 定位第i-1个节点
{
cc ++;
p = p->next;
}
LL *s = p->next; // s指向第i个节点
p->next = s->next; // 从链表中删除
free(s); // 释放*s
lcount --;
printlist();
return 0;
}
int main()
{
if( !readin() )
{
Del_LinkList( I );
}
return 0;
}
Java代码实现
一、单向链表(插入、删除、遍历、反转、合并两个有序链表)
1. 定义结点类
public class Node {
int data;
Node next; //指向下一个节点
public Node(int data) {
this.data = data;
}
}
2. 实现单链表的建立、插入、遍历以及删除,还有链表反转,合并两个有序链表等操作
//实现链表的建立、插入、遍历以及删除
public class SingleLinkedList {
//头结点(不是首元结点,注意两者区别)
private Node head = new Node(-1);
public Node getHead() {
return this.head;
}
public void setHead(Node head) {
this.head = head;
}
//将每个节点添加到链表的最后一个节点
public void buildByLast(Node node) {
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = node;
}
//将每个节点按顺序插入到链表中
public void buildByOrder(Node node) {
Node temp = head;
boolean flag = false; //判断是否已插入
while (temp.next != null) {
if (temp.next.data > node.data) { //找到位置,插入节点
node.next = temp.next;
temp.next = node;
flag = true;
break;
}
temp = temp.next;
}
if (!flag) { //还没插入,就把node结点插到最后一个
temp.next = node;
}
}
//删除结点
public void deleteNode(int n) {
if (head.next == null) {
System.out.println("列表为空");
return;
}
Node temp = head;
boolean flag = false; //判断是否已删除
while (temp.next != null) {
if (temp.next.data == n) {
temp.next = temp.next.next;
flag = true;
break;
}
temp = temp.next;
}
if (!flag) {
System.out.println("没有找到该结点");
}
}
//遍历每个结点
public void getAll() {
Node temp = head.next;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
//单链表反转 写法1
//(头结点插入法:把每一个结点从原来位置删除,然后插入到头结点后面,最终完成反转)
public void reverseNode1() {
/*链表为空或只有一个元素则直接返回*/
if (head.next == null || head.next.next == null) {
return;
}
Node temp1 = head.next;
Node temp2 = null;
Node temp3 = temp1; //temp3为头结点的下一个结点
while (temp1.next != null) {
temp2 = temp1.next;
//删掉temp2结点
temp1.next = temp1.next.next;
//把temp2结点插入到头结点后面
temp2.next = temp3;
head.next = temp2;
//使temp3重新成为头结点的下一个结点
temp3 = temp2;
}
}
//单链表反转 写法2
//原地反转法
public void reverseNode2() {
/*链表为空或只有一个元素则直接返回*/
if (head.next == null || head.next.next == null) {
return;
}
Node t = null;
Node p = head.next ;
Node q = head.next.next;
while (q != null) {
t = q.next;
q.next = p;
p = q;
q = t;
}
/*此时q指向原始链表最后一个元素,也是逆转后的链表的表头元素*/
head.next.next = null; /*设置链表尾*/
head.next = p; /*调整链表头*/
}
//两个有序单链表的合并(单链表包含头结点)
public static Node combine(Node head1, Node head2) {
Node t1 = head1.next;
Node t2 = head2.next;
Node headNode = new Node(-1);
Node finalHead = headNode;
while (t1 != null && t2 != null) {
if (t1.data < t2.data) {
headNode.next = t1;
t1 = t1.next;
} else {
headNode.next = t2;
t2 = t2.next;
}
headNode = headNode.next;
}
if (t1 == null) {
headNode.next = t2;
} else if (t2 == null){
headNode.next = t1;
}
return finalHead;
}
}
3. 测试
测试插入、遍历、反转、删除操作
import java.util.Scanner;
public class TestSingleLinkedList {
public static void main(String[] args) {
SingleLinkedList linkList = new SingleLinkedList();
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
//linkList.buildByLast(new Node(sc.nextInt())); //直接插最后
linkList.buildByOrder(new Node(sc.nextInt())); //按大小插入
}
linkList.getAll(); //遍历输出
linkList.reverseNode1(); //反转
linkList.getAll(); //遍历输出
linkList.reverseNode2(); //反转
linkList.getAll(); //遍历输出
while (true) {
linkList.deleteNode(sc.nextInt()); //删除结点
linkList.getAll(); //遍历输出
}
}
}
测试合并两个有序链表
import java.util.Scanner;
public class TestSingleLinkedList {
public static void main(String[] args) {
SingleLinkedList linkList1 = new SingleLinkedList();
SingleLinkedList linkList2 = new SingleLinkedList();
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
linkList1.buildByOrder(new Node(sc.nextInt())); //按大小插入
}
int n1 = sc.nextInt();
for (int i = 0; i < n1; i++) {
linkList2.buildByOrder(new Node(sc.nextInt())); //按大小插入
}
linkList1.getAll(); //遍历输出
linkList2.getAll(); //遍历输出
//合并两个有序链表
Node head = SingleLinkedList.combine(linkList1.getHead(), linkList2.getHead());
//结果输出
SingleLinkedList l1 = new SingleLinkedList();
l1.setHead(head);
l1.getAll(); //合并后的链表遍历输出
}
}
二、双向链表(插入、删除、遍历)
1. 定义结点类
class Node1 {
int data;
Node1 next; //指向下一个节点
Node1 pre; //指向上一个节点
public Node1(int data) {
this.data = data;
}
}
2. 实现双向链表的创建、插入、遍历以及删除
public class DoublyLinkedList {
//头结点
private Node1 head = new Node1(-1);
//将每个节点添加到链表的最后一个节点
void buildByLast(Node1 node) {
Node1 temp = head;
while(temp.next != null) {
temp = temp.next;
}
//当前节点的pre指向前面的链表
node.pre = temp;
//最后一个节点的next指向node
temp.next = node;
}
//删除节点
public void deleteNode(int n) {
if (head.next == null) {
System.out.println("列表为空");
return;
}
boolean flag = false;//标记是否已删除
Node1 temp = head.next;
while(temp != null) {
if (temp.data == n) {
temp.pre.next = temp.next;
flag = true;
break;
}
temp = temp.next;
}
if (!flag) {
System.out.println("没有找到该节点");
return;
}
if (temp.next != null) {
temp.next.pre = temp.pre;
}
}
//遍历每个节点
public void getAll() {
Node1 temp = head.next;
while(temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
}
3. 测试
import java.util.Scanner;
public class TestDoublyLinkedList {
public static void main(String[] args) {
DoublyLinkedList linkList = new DoublyLinkedList();
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++) {
linkList.buildByLast(new Node1(sc.nextInt())); //直接插最后
}
linkList.getAll(); //遍历输出
while (true) {
linkList.deleteNode(sc.nextInt()); //删除结点
linkList.getAll(); //遍历输出
}
}
}
三、循环链表解决约瑟夫问题
1.创建环形链表解决约瑟夫问题:
public class CircleLinkedList {
private Node first = null; //设置为环形链表的第一个节点,即首元结点
//创建环形链表
public void build(int nums) {
//定义当前节点
Node cur = null;
for(int i=1; i <= nums; i++) {
Node circleLink = new Node(i);
if (i==1) { //只有一个节点时,next指向自己
first = circleLink;
circleLink.next = first;
} else {
cur.next = circleLink;
circleLink.next = first;
}
cur = circleLink;
}
}
//约瑟夫问题删除第k个节点
public void deleteNode(int k) {
Node cur = first; //当前节点
Node q = first; //当前节点的前一个节点
//找到首元节点的前一个节点
while (q.next != first) {
q = q.next;
}
int i = 1; //定义初始位置
while(true) {
if (q == cur) { //只剩一个节点
System.out.println("最终剩余节点:" + cur.data);
break;
}
if (i == k) { //找到要删除的节点位置
System.out.println("删除节点:" + cur.data);
q.next = cur.next;
cur = cur.next;
i=1; //初始位置重新定为1
continue;
}
i++;
cur = cur.next;
q = q.next;
}
first = cur;
cur.next = first;
}
//遍历环形链表
public void getAll() {
Node w = first;
while (w.next != first) {
System.out.print(w.data + " ");
w = w.next;
}
System.out.println(w.data);
}
}
2. 测试:
import java.util.Scanner;
import java.util.Timer;
public class TestCircileLinkedList {
public static void main(String[] args) {
CircleLinkedList cirLinkList = new CircleLinkedList();
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //输入n个节点
int m = sc.nextInt(); //删除约瑟夫循环的第m个位置
for (int i = 1; i <= n; i++) {
cirLinkList.build(i);
}
cirLinkList.getAll();
cirLinkList.deleteNode(m);
cirLinkList.getAll();
}
}
/**
7 2
1 2 3 4 5 6 7
删除节点:2
删除节点:4
删除节点:6
删除节点:1
删除节点:5
删除节点:3
最终剩余节点:7
7
*/